<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 7.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.ico">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.ico">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha256-wiz7ZSCn/btzhjKDQBms9Hx4sSeUYsDrTLg7roPstac=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.css" integrity="sha256-6cQIC71/iBIYXFK+0RHAvwmjwWzkWd+r7v/BX3/vZDc=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/themes/green/pace-theme-minimal.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/pace.min.js" integrity="sha256-gqd7YTjg/BtfqWSwsJOvndl0Bxc8gFImLEkXQT8+qj0=" crossorigin="anonymous"></script>

<script class="next-config" data-name="main" type="application/json">{"hostname":"sumumm.github.io","root":"/","images":"/images","scheme":"Gemini","darkmode":false,"version":"8.19.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":"mac"},"fold":{"enable":true,"height":300},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":true,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content="本文主要是STM32基础知识的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:type" content="article">
<meta property="og:title" content="LV16-03-STM32基础知识">
<meta property="og:url" content="https://sumumm.github.io/post/c2c37802.html">
<meta property="og:site_name" content="苏木">
<meta property="og:description" content="本文主要是STM32基础知识的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417223005421.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417223152126.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417223503942.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230408162122910.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420215031690.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420215214197.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420215311634.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420215929780.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420224355525.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420224605541.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420225046300.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420225341112.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420230207229.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230408162420343.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230408162808406.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230408162919664.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230408164622525.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230408164718576.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230408165138311.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417225559820.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417225902352.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417230846857.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417231317291.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417231355101.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417231603407.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417231931946.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417232058730.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417232300976.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230418221356751.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230501164207687.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230501170931048.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230501174643348.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420231930503.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420232215474.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113112812542.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113113102109.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113113729681.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420233318141.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230421193945130.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230421194328019.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230421194453728.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230421194755261.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113114453925.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113114632225.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230421200129597.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230421215634134.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113115532703.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113115609165.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113120512319.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230421222938085.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113121103358.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113114126151.png">
<meta property="article:published_time" content="2023-06-04T14:06:25.000Z">
<meta property="article:modified_time" content="2025-06-13T16:25:57.006Z">
<meta property="article:author" content="苏木">
<meta property="article:tag" content="LV16-STM32开发">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417223005421.png">


<link rel="canonical" href="https://sumumm.github.io/post/c2c37802.html">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"https://sumumm.github.io/post/c2c37802.html","path":"post/c2c37802.html","title":"LV16-03-STM32基础知识"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>LV16-03-STM32基础知识 | 苏木</title>
  








    <script src="/js/browser_tools_disable.js"></script>

  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
<!-- hexo injector head_end start --><link rel="stylesheet" href="https://unpkg.com/hexo-next-tags-plus@latest/lib/tag_plus.css" media="defer" onload="this.media='all'"><!-- hexo injector head_end end --></head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">苏木</p>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">我的学习之路</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>苏木的家</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类页<span class="badge">42</span></a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档页<span class="badge">673</span></a></li><li class="menu-item menu-item-flink"><a href="/flink/" rel="section"><i class="fa fa-link fa-fw"></i>友人帐</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于我</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%80%E3%80%81STM32%E7%AE%80%E4%BB%8B"><span class="nav-text">一、STM32简介</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-STM32%E4%B8%8EARM"><span class="nav-text">1. STM32与ARM</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-STM32%E8%B5%84%E6%96%99"><span class="nav-text">2. STM32资料</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-ST%E5%AE%98%E7%BD%91"><span class="nav-text">2.1 ST官网</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-1-%E6%90%9C%E7%B4%A2%EF%BC%9F"><span class="nav-text">2.1.1 搜索？</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-2-%E6%96%87%E6%A1%A3%EF%BC%9F"><span class="nav-text">2.1.2 文档？</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-3-%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7%EF%BC%9F"><span class="nav-text">2.1.3 开发工具？</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-4-%E5%9B%BA%E4%BB%B6%E5%8C%85%EF%BC%9F"><span class="nav-text">2.1.4 固件包？</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-5-%E6%A0%87%E5%87%86%E5%A4%96%E8%AE%BE%E5%BA%93%EF%BC%9F"><span class="nav-text">2.1.5 标准外设库？</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-ST%E4%B8%AD%E6%96%87%E5%AE%98%E7%BD%91"><span class="nav-text">2.2 ST中文官网</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-3-ST%E7%A4%BE%E5%8C%BA"><span class="nav-text">2.3 ST社区</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%8C%E3%80%81%E6%9C%80%E5%B0%8F%E7%B3%BB%E7%BB%9F"><span class="nav-text">二、最小系统</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E7%94%B5%E6%BA%90%E7%94%B5%E8%B7%AF"><span class="nav-text">1. 电源电路  </span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E6%97%B6%E9%92%9F%E7%94%B5%E8%B7%AF"><span class="nav-text">2. 时钟电路  </span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E5%A4%8D%E4%BD%8D%E7%94%B5%E8%B7%AF"><span class="nav-text">3. 复位电路</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-%E8%B0%83%E8%AF%95-%E4%B8%8B%E8%BD%BD%E7%94%B5%E8%B7%AF"><span class="nav-text">4. 调试&#x2F;下载电路</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-1-JTAG%E5%8D%8F%E8%AE%AE%E7%AE%80%E4%BB%8B"><span class="nav-text">4.1 JTAG协议简介</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-2-SWD%E5%8D%8F%E8%AE%AE%E7%AE%80%E4%BB%8B"><span class="nav-text">4.2 SWD协议简介</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5-%E5%90%AF%E5%8A%A8%E9%80%89%E6%8B%A9%E7%94%B5%E8%B7%AF"><span class="nav-text">5. 启动选择电路  </span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%89%E3%80%81%E5%B5%8C%E5%85%A5%E5%BC%8FC%E8%AF%AD%E8%A8%80"><span class="nav-text">三、嵌入式C语言</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-STM32%E6%94%AF%E6%8C%81%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B"><span class="nav-text">1. STM32支持的数据类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E4%BD%8D%E8%BF%90%E7%AE%97"><span class="nav-text">2. 位运算</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="nav-text">2.1 运算符</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-%E6%B8%850%E6%88%96%E7%BD%AE1"><span class="nav-text">2.2 清0或置1</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E9%9D%9E%E7%9A%84%E4%BD%BF%E7%94%A8"><span class="nav-text">3. 非的使用</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-weak%E4%B8%8E-attribute-weak"><span class="nav-text">4. __weak与__attribute__((weak))</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-1-%E4%B8%A4%E8%80%85%E5%85%B3%E7%B3%BB"><span class="nav-text">4.1 两者关系</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-2-%E5%BC%BA%E5%BC%B1%E7%AC%A6%E5%8F%B7"><span class="nav-text">4.2 强弱符号</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-3-weak%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%9C%A8%E5%93%AA%EF%BC%9F"><span class="nav-text">4.3 __weak可以用在哪？</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#4-3-1-%E5%A3%B0%E6%98%8E"><span class="nav-text">4.3.1 声明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-3-2-%E5%AE%9A%E4%B9%89"><span class="nav-text">4.3.2 定义</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-4-weak%E4%BD%BF%E7%94%A8%E7%9A%84%E9%99%90%E5%88%B6"><span class="nav-text">4.4 __weak使用的限制</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-5-attribute-weak-%E7%94%A8%E5%9C%A8%E5%93%AA%EF%BC%9F"><span class="nav-text">4.5 __attribute__((weak))用在哪？</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#4-5-1-%E5%A3%B0%E6%98%8E"><span class="nav-text">4.5.1 声明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-5-2-%E5%AE%9A%E4%B9%89"><span class="nav-text">4.5.2 定义</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-6-%E4%B8%A4%E8%80%85%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="nav-text">4.6 两者的区别</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%9B%9B%E3%80%81STM32%E5%BC%80%E5%8F%91"><span class="nav-text">四、STM32开发</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E5%BC%80%E5%8F%91%E6%96%B9%E5%BC%8F"><span class="nav-text">1. 开发方式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E5%BA%93%E5%BC%80%E5%8F%91%E4%B8%8E%E5%AF%84%E5%AD%98%E5%99%A8%E5%BC%80%E5%8F%91%E7%9A%84%E5%85%B3%E7%B3%BB"><span class="nav-text">2. 库开发与寄存器开发的关系  </span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-STM32-%E5%9B%BA%E4%BB%B6%E5%BA%93%E4%B8%8E-CMSIS-%E6%A0%87%E5%87%86"><span class="nav-text">3. STM32 固件库与 CMSIS 标准</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-1-CMSIS%E7%9A%84%E6%9D%A5%E5%8E%86"><span class="nav-text">3.1  CMSIS的来历</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-CMSIS-%E6%A0%87%E5%87%86"><span class="nav-text">3.2 CMSIS 标准  </span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-%E4%B8%89%E7%A7%8D%E5%AE%98%E6%96%B9%E5%BA%93"><span class="nav-text">4. 三种官方库</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-1-%E6%A0%87%E5%87%86%E5%A4%96%E8%AE%BE%E5%BA%93"><span class="nav-text">4.1 标准外设库</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#4-1-1-%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD"><span class="nav-text">4.1.1 文件下载</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-1-2-%E6%A0%87%E5%87%86%E5%BA%93%E4%BB%8B%E7%BB%8D"><span class="nav-text">4.1.2 标准库介绍</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-1-3-%E5%85%B3%E9%94%AE%E6%96%87%E4%BB%B6%E4%BB%8B%E7%BB%8D"><span class="nav-text">4.1.3 关键文件介绍</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-2-HAL%E5%BA%93"><span class="nav-text">4.2 HAL库  </span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#4-2-1-HAL%E5%BA%93%E8%83%BD%E5%81%9A%E4%BB%80%E4%B9%88"><span class="nav-text">4.2.1 HAL库能做什么</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-2-2-%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD"><span class="nav-text">4.2.2 文件下载</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-2-3-HAL%E5%BA%93%E4%BB%8B%E7%BB%8D"><span class="nav-text">4.2.3 HAL库介绍</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-2-4-CMSIS-%E6%96%87%E4%BB%B6%E5%A4%B9%E5%85%B3%E9%94%AE%E6%96%87%E4%BB%B6"><span class="nav-text">4.2.4 CMSIS 文件夹关键文件  </span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-2-5-%E5%85%B3%E9%94%AE%E6%96%87%E4%BB%B6%E4%BB%8B%E7%BB%8D%E8%A1%A5%E5%85%85%E7%AC%94%E8%AE%B0"><span class="nav-text">4.2.5 关键文件介绍补充笔记</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-2-6-weak-%E4%BF%AE%E9%A5%B0%E7%AC%A6"><span class="nav-text">4.2.6 __weak 修饰符  </span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-2-7-Msp-%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B"><span class="nav-text">4.2.7 Msp 回调函数执行过程  </span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#4-2-8-HAL%E5%BA%93%E4%B8%AD%E6%96%AD%E5%A4%84%E7%90%86"><span class="nav-text">4.2.8 HAL库中断处理</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-3-LL%E5%BA%93"><span class="nav-text">4.3 LL库</span></a></li></ol></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="苏木"
      src="/images/avatar.jpg">
  <p class="site-author-name" itemprop="name">苏木</p>
  <div class="site-description" itemprop="description">莫道桑榆晚，为霞尚满天</div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">673</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">42</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
        <span class="site-state-item-count">43</span>
        <span class="site-state-item-name">标签</span>
      </div>
  </nav>
</div>
  <div class="links-of-author animated">
      <span class="links-of-author-item">
        <a href="https://github.com/sumumm" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;sumumm" rel="noopener me" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
  </div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://sumumm.github.io/post/c2c37802.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.jpg">
      <meta itemprop="name" content="苏木">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="苏木">
      <meta itemprop="description" content="莫道桑榆晚，为霞尚满天">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="LV16-03-STM32基础知识 | 苏木">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          LV16-03-STM32基础知识
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-06-04 22:06:25" itemprop="dateCreated datePublished" datetime="2023-06-04T22:06:25+08:00">2023-06-04</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/" itemprop="url" rel="index"><span itemprop="name">嵌入式开发</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/" itemprop="url" rel="index"><span itemprop="name">01HQ课程体系</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/" itemprop="url" rel="index"><span itemprop="name">LV16-STM32开发</span></a>
        </span>
    </span>

  
    <span class="post-meta-break"></span>
    <span class="post-meta-item" title="本文字数">
      <span class="post-meta-item-icon">
        <i class="far fa-file-word"></i>
      </span>
      <span class="post-meta-item-text">本文字数：</span>
      <span>23k</span>
    </span>
    <span class="post-meta-item" title="阅读时长">
      <span class="post-meta-item-icon">
        <i class="far fa-clock"></i>
      </span>
      <span class="post-meta-item-text">阅读时长 &asymp;</span>
      <span>1:24</span>
    </span>
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody"><p>本文主要是STM32基础知识的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。</p>
<span id="more"></span>

<!-- Photo: https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/ -->

<details class="folding-tag" blue><summary> 点击查看使用工具及版本 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center" width=150px>Windows</td>        <td align="left">windows11</td>    </tr>    <tr>        <td align="center">Ubuntu</td>        <td align="left">Ubuntu16.04的64位版本</td>      </tr>    <tr>        <td align="center">VMware® Workstation 16 Pro</td>        <td align="left">16.2.3 build-19376536</td>      </tr>    <tr>        <td align="center">SecureCRT</td>        <td align="left">Version 8.7.2 (x64 build 2214)   -   正式版-2020年5月14日</td>      </tr>    <tr>        <td align="center">开发板</td>        <td align="left">正点原子 i.MX6ULL Linux阿尔法开发板</td>      </tr>    <tr>        <td align="center">uboot</td>        <td align="left">NXP官方提供的uboot，NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)</td>      </tr>    <tr>        <td align="center">linux内核</td>        <td align="left">linux-4.15(NXP官方提供)</td>      </tr>    <tr>        <td align="center">STM32开发板</td>        <td align="left">正点原子战舰V3(STM32F103ZET6)</td>      </tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看本文参考资料 </summary>
              <div class='content'>
              <ul><li>通用</li></ul><table><tr><td align="center">分类  </td><td align="center">网址</td><td align="center">说明</td></tr><tr><td align="center" rowspan="4">官方网站</td><td align="left"><a href="https://www.arm.com/" target="_blank">https://www.arm.com/</a></td><td align="left">ARM官方网站，在这里我们可以找到Cotex-Mx以及ARMVx的一些文档</td></tr><tr>                                            <td align="left"><a href="https://www.st.com/content/st_com/zh.html" target="_blank">https://www.st.com/content/st_com/zh.html</a></td><td align="left">ST官方网站，在这里我们可以找到STM32的相关文档</td></tr><tr>                                            <td align="left"><a href="https://www.stmcu.com.cn/" target="_blank">https://www.stmcu.com.cn/</a></td><td align="left">意法半导体ST中文官方网站，在这里我们可以找到STM32的相关中文参考文档</td></tr><tr>                                            <td align="left"><a href="http://elm-chan.org/fsw/ff/00index_e.html" target="_blank">http://elm-chan.org/fsw/ff/00index_e.html</a></td><td align="left">FatFs文件系统官网</td></tr><tr><td align="center" rowspan="3">教程书籍</td><td align="left"><a href="STM32开发相关资料/01ARM参考资料/ARM Cortex-M3权威指南(中文).pdf" target="_blank">《ARM Cortex-M3权威指南》</a></td><td alirn="left" rowspan="3">ARM公司专家Joseph Yiu（姚文祥）的力作，中文翻译是NXP的宋岩</td></tr><tr>                                            <td align="left"><a href="STM32开发相关资料/01ARM参考资料/ARM Cortex-M0权威指南(中文).pdf" target="_blank">《ARM Cortex-M0权威指南》</a></td></tr><tr>                                            <td align="left"><a href="" target="_blank">《ARM Cortex-M3与Cortex-M4权威指南》</a></td></tr><tr><td align="center" rowspan="4">开发论坛</td><td align="left"><a href="http://47.111.11.73/forum.php" target="_blank">http://47.111.11.73/forum.php</a></td><td align="left">开源电子网，正点原子的资料下载及问题讨论论坛</td></tr><tr>                                            <td align="left"><a href="https://www.firebbs.cn/forum.php" target="_blank">https://www.firebbs.cn/forum.php</a></td><td align="left">国内Kinetis开发板-野火/秉火（刘火良）主持的论坛，现也做STM32和i.MX RT</td></tr><tr>                                            <td align="left"><a href="https://www.amobbs.com/index.php" target="_blank">https://www.amobbs.com/index.php</a></td><td align="left">阿莫（莫进明）主持的论坛，号称国内最早最火的电子论坛，以交流Atmel AVR系列单片机起家，现已拓展到嵌入式全平台，其STM32系列帖子有70W+。</td></tr><tr>                                            <td align="left"><a href="http://download.100ask.net/index.html" target="_blank">http://download.100ask.net/index.html</a></td><td align="left">韦东山嵌入式资料中心，有些STM32和linux的相关资料也可以来这里找。</td></tr><tr><td align="center" rowspan="3">博客参考</td><td align="left"><a href="http://www.openedv.com/" target="_blank">http://www.openedv.com/</a></td><td align="left">开源网-原子哥个人博客</td></tr><tr>                                            <td align="left"><a href="http://blog.chinaaet.com/jihceng0622" target="_blank">http://blog.chinaaet.com/jihceng0622</a></td><td align="left">博主是原Freescale现NXP的现场应用工程师</td></tr><tr>                                            <td align="left"><a href="https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/cortex-m-resources" target="_blank">cortex-m-resources</a></td><td align="left">这其实并不算是一个博客，这是ARM公司专家Joseph Yiu收集整理的所有对开发者有用的官方Cortex-M资料链接（也包含极少数外部资源链接）</td></tr></table><ul><li>STM32</li></ul><table>    <tr><td align="center" rowspan="2">STM32</td><td align="left"><a href="https://doc.embedfire.com/mcu/stm32/f103/hal_general/zh/latest/index.html" target="_blank">STM32 HAL库开发实战指南——基于F103系列开发板</a></td><td align="left">野火STM32开发教程在线文档</td></tr><tr>                                            <td align="left"><a href="https://doc.embedfire.com/mcu/stm32/f103badao/std/zh/latest/index.html" target="_blank">STM32库开发实战指南——基于野火霸道开发板</a></td><td align="left">野火STM32开发教程在线文档</td></tr></table><ul><li>SD卡</li></ul><table>    <tr><td align="left"><a href="https://www.sdcard.org/" target="_blank">SD Association</a></td><td align="left">提供了SD存储卡和SDIO卡系统规范</td></tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看相关文件下载 </summary>
              <div class='content'>
              <table>    <tr><td align="left"><a href="https://www.st.com/resource/en/datasheet/stm32f103ze.pdf" target="_blank">STM32F103xx英文数据手册</a></td><td align="left">STM32F103xC/D/E系列的英文数据手册</td></tr>    <tr><td align="left"><a href="https://www.stmcu.com.cn/Designresource/detail/localization_document%20/709978" target="_blank">STM32F103xx中文数据手册</a></td><td align="left">STM32F103xC/D/E系列的中文数据手册</td></tr>    <tr><td align="left"><a href="https://www.st.com/resource/en/reference_manual/rm0008-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf" target="_blank">STM32F10xxx英文参考手册（RM0008）</a></td><td align="left">STM32F10xxx系列的英文参考手册</td></tr>    <tr><td align="left"><a href="https://www.stmcu.com.cn/Designresource/detail/localization_document%20/710001" target="_blank">STM32F10xxx中文参考手册（RM0008）</a></td><td align="left">STM32F10xxx系列的中文参考手册</td></tr>    <tr><td align="left"><a href="https://developer.arm.com/documentation/100165/0201/?lang=en" target="_blank">Arm Cortex-M3 处理器技术参考手册-英文版</a></td><td align="left">Cortex-M3技术参考手册-英文版</td></tr>    <tr><td align="left"><a href="https://www.st.com/resource/en/programming_manual/pm0056-stm32f10xxx20xxx21xxxl1xxxx-cortexm3-programming-manual-stmicroelectronics.pdf" target="_blank">STM32F10xxx Cortex-M3编程手册-英文版(PM0056)</a></td><td align="left">STM32F10xxx/20xxx/21xxx/L1xxxx系列Cortex-M3编程手册-英文版</td></tr>    <tr><td align="left"><a href="https://www.sdcard.org/downloads/pls/" target="_blank">SD卡相关资料——最新版本</a></td><td align="left">有关SD卡的一些资料可以从这里下载</td></tr>    <tr><td align="left"><a href="https://www.sdcard.org/downloads/pls/archives/" target="_blank">SD卡相关资料——历史版本</a></td><td align="left">有关SD卡的一些历史版本资料可以从这里下载，比如后边看的SD卡2.0协议</td></tr>    <tr><td align="left"><a href="./" target="_blank">SD 2.0 协议标准完整版</a></td><td align="left">这是一篇关于SD卡2.0协议的中文文档，还是比较有参考价值的，可以一看</td></tr></table>
              </div>
            </details> 

<h1 id="一、STM32简介"><a href="#一、STM32简介" class="headerlink" title="一、STM32简介"></a><font size=3>一、STM32简介</font></h1><h2 id="1-STM32与ARM"><a href="#1-STM32与ARM" class="headerlink" title="1. STM32与ARM"></a><font size=3>1. STM32与ARM</font></h2><p>在2004年， ARM公司推出新一代Cortex内核后， ST公司抓住机遇，在很短的时间内就向市场推出了一系列的32位微控制器， 同时提供基于库的开发模式，加快用户研发周期。 STM32就是ST公司基于ARM Cortex-M系列内核设计的微控制器，专为高性能、低功耗、低成本场景设计。  </p>
<p>STM32如今产品系列非常丰富， 主要为ARM Cortex-M内核系列MCU，也开始涉及ARM Cortex-A内核<br>系列MPU，如下图所示。 </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417223005421.png" alt="image-20230417223005421" style="zoom:50%;" />

<p>按应用特性分类，可分为无线WB&#x2F;WL系列、超低功耗L0&#x2F;L1&#x2F;L3&#x2F;L5系列、主流G0&#x2F;G4&#x2F;F0&#x2F;F1&#x2F;F3系列、高性能F2&#x2F;F4&#x2F;F7&#x2F;H7系列、全新的MP1系列。  </p>
<p>STM32的处理器种类众多， 通过了解STM32的命令规范，可以了解整个STM32家族产品， 也方便以后<br>芯片选型， STM32 MCU系列命名规则（STM32 芯片命名规则，下图仅适用于 MCU） ：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417223152126.png" alt="image-20230417223152126" style="zoom:50%;" />

<p>其实每一款芯片都会有一个datasheet，也就是数据手册，在数据手册中会对芯片的命名有详细的说明，例如：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417223503942.png" alt="image-20230417223503942" style="zoom:50%;" />

<p>总的来说ARM公司售卖Cortex-M系列的授权， 意法半导体(STMicroelectronics， ST)购买了该授权，生产了一些列STM32产品， 这些使用ARM技术的处理器，都习惯称为ARM处理器 。</p>
<h2 id="2-STM32资料"><a href="#2-STM32资料" class="headerlink" title="2. STM32资料"></a><font size=3>2. STM32资料</font></h2><p>这一部分主要是记录一下查找ARM和STM32官方文档的时候的一些相关链接。</p>
<h3 id="2-1-ST官网"><a href="#2-1-ST官网" class="headerlink" title="2.1 ST官网"></a><font size=3>2.1 ST官网</font></h3><ul>
<li>ST官网：<a target="_blank" rel="noopener" href="https://www.st.com/content/st_com/zh.html">意法半导体-STMicroelectronics</a></li>
</ul>
<p>这个网站是ST的官方网站，所有的文档都可以从这里找，例如STM32相关的内容，我们就可以进入【产品】&rarr;【微控制器与微处理器】，然后我们点进入就可以看到相关的产品及相关资料啦。</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230408162122910.png" alt="image-20230408162122910" style="zoom: 18%;" />

<p>对于几乎所有的MCU，都会有<strong>数据手册</strong>和<strong>参考手册</strong>，这两个手册必须下载。对于STM32系列的MCU， 通常还会有<strong>Cortex-M3&#x2F;M4编程手册</strong>， <strong>闪存编程手册</strong>、 勘误手册、<strong>官方固件包示例源码</strong>、官方固件包用户手册、 <strong>HAL库用户手册</strong>等，这些资料根据需求下载。  对于Cortex-M3&#x2F;M4架构的的MCU， 如果需要深入了解Cortex-M3&#x2F;M4内核，还需要<strong>Cortex-M3&#x2F;M4权威指南</strong>，这个供我们深入学习。  </p>
<h4 id="2-1-1-搜索？"><a href="#2-1-1-搜索？" class="headerlink" title="2.1.1 搜索？"></a><font size=3>2.1.1 搜索？</font></h4><p>我们以STM32F103ZET6为例来看一看资料都在哪里：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420215031690.png" alt="image-20230420215031690" style="zoom:25%;" />

<p>随后显示该搜索条件匹配的产品，如下图所示，可以看到只有一款产品符合搜索条件，点击该产品进入详细信息。  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420215214197.png" alt="image-20230420215214197" style="zoom:18%;" />

<h4 id="2-1-2-文档？"><a href="#2-1-2-文档？" class="headerlink" title="2.1.2 文档？"></a><font size=3>2.1.2 文档？</font></h4><p>在产品详细页，切换到“Documentation”标签， 可以看到该产品的所有文档手册，如下图所示为部分截图。  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420215311634.png" alt="image-20230420215311634" style="zoom:18%;" />

<p>后来网站都显示为中文了，如果打开都是英文页面的话，对应如下：</p>
<ul>
<li><p>“ Product Specifications”(产品规格)：也就是数据手册， 包含该系列MCU的整体描述、引脚描述、内存映射、电气特性、封装信息、订购信息等。在芯片选型、 原理图设计、 PCB设计、代码编程等开发环节，都会需要该文档；</p>
</li>
<li><p>“ Reference Manuals”(参考手册)： 包含该系列MCU各外设寄存器的详细描述， 在代码编程时，需要找到对应外设章节， 仔细阅读；</p>
</li>
<li><p>“ Programming Manuals”(编程手册)： 包含闪存编程手册和Cortex-M3内核编程手册， 一些资源是在内核里的，比如NVIC和SysTick， 此时在参考手册里找不到相关寄存器信息，就需要在Cortex-M3内核编程手册里查找；</p>
</li>
<li><p>“ Errata Sheets”（ 勘误手册） ： 包含该MCU内核、 外设资源的限制，解决方案等，在调试中出现了bug，可以看看该手册是否有类似记录；</p>
</li>
</ul>
<h4 id="2-1-3-开发工具？"><a href="#2-1-3-开发工具？" class="headerlink" title="2.1.3 开发工具？"></a><font size=3>2.1.3 开发工具？</font></h4><p>除了这些文档外， 通常半导体芯片制造厂还会为MCU提供一些示例程序， ST也不例外。 在前面的产品详细页，切换到“ Tools &amp; Software”标签，可以看到该产品的所有工具软件，比如各种硬件开发工具、软件开发工具、元件模块、评估工具软件、 MCU&#x2F;MPU嵌入式软件、 产品评估工具、解决方案评估工具、工程服务、培训课程等 ：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420215929780.png" alt="image-20230420215929780" style="zoom:18%;" />

<p>比如我们可以在这里找到Keil MDK开发工具：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420224355525.png" alt="image-20230420224355525" style="zoom:25%;" />

<p>还可以找到图形化开发工具STM32CubeMX，不过这里好像链接有些问题，点进去什么也没得，不过问题不大：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420224605541.png" alt="image-20230420224605541" style="zoom:25%;" />

<h4 id="2-1-4-固件包？"><a href="#2-1-4-固件包？" class="headerlink" title="2.1.4 固件包？"></a><font size=3>2.1.4 固件包？</font></h4><p>在上边开发工具里还会有一个 MCU &amp; MPU Embedded  Software  的栏目，也就是 MCU 及 MPU嵌入式软件：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420225046300.png" alt="image-20230420225046300" style="zoom:25%;" />

<p>我们下载下来看一下，我们点进去后点击 Get Software就会来到下载的页面，选择和这个Get latest，然后会让我们登录，登录后就可以下载了。</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420225341112.png" alt="image-20230420225341112" style="zoom: 33%;" />

<h4 id="2-1-5-标准外设库？"><a href="#2-1-5-标准外设库？" class="headerlink" title="2.1.5 标准外设库？"></a><font size=3>2.1.5 标准外设库？</font></h4><p>之前学习的时候最开始学习的就是标准库开发，那库在哪里下载？</p>
<p>在这里【官网】&rarr;【工具与软件】&rarr;【嵌入式软件】&rarr;【微控制器软件】&rarr;【STM32微控制器软件】</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420230207229.png" alt="image-20230420230207229" style="zoom:25%;" />

<p>比如图中的标准库：<a target="_blank" rel="noopener" href="https://www.st.com/zh/embedded-software/stm32-standard-peripheral-libraries.html">STM32标准外设软件库 - 意法半导体STMicroelectronics</a></p>
<h3 id="2-2-ST中文官网"><a href="#2-2-ST中文官网" class="headerlink" title="2.2 ST中文官网"></a><font size=3>2.2 ST中文官网</font></h3><ul>
<li>STMCU中文官网：<a target="_blank" rel="noopener" href="https://www.stmcu.com.cn/">STMCU中文官网</a></li>
</ul>
<p>这里会有大量的中文文档，好像也是ST的官方网站，我们想要找自己使用的芯片的相关文档的话，就可以从下图的地方寻找：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230408162420343.png" alt="image-20230408162420343" style="zoom:20%;" />

<p>那我们平时在网上看到的那些中文文档在哪里呢？我们可以进入首页后【设计资源】&rarr;【中英译文】</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230408162808406.png" alt="image-20230408162808406" style="zoom:20%;" />

<p>然后在下边选择我们的单片机的系列，这样就可以找到一些相关的中文文档啦，不过这里似乎不太好用，因为我没找到我想找的中文文档。</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230408162919664.png" alt="image-20230408162919664" style="zoom:20%;" />

<p>然后一看，右上角不是有搜索框嘛，这不试一下？我们以STM32F1为例，搜索结果如下：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230408164622525.png" alt="image-20230408164622525" style="zoom:20%;" />

<p>然后这里就会显示所有相关的中文的文档啦，下图中框的，我们打开看的话就会发现，这个文档就是我们平时看到的STM32中文参考文档的资料啦</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230408164718576.png" alt="image-20230408164718576" style="zoom:25%;" />

<p>我们下载下来后，以正点原子提供的参考资料为准对比一下，看看是不是就是这一个，对比发现，是一样的，所以呢，我们完全可以从官网找到一些相关的中文文档。</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230408165138311.png" alt="image-20230408165138311" style="zoom:25%;" />

<h3 id="2-3-ST社区"><a href="#2-3-ST社区" class="headerlink" title="2.3 ST社区"></a><font size=3>2.3 ST社区</font></h3><p>有一些资料我们也可以去ST的社区查找：<a target="_blank" rel="noopener" href="https://www.stmcu.org.cn/">意法半导体STM32&#x2F;STM8技术社区 - 提供最新的ST资讯和技术交流 (stmcu.org.cn)</a></p>
<h1 id="二、最小系统"><a href="#二、最小系统" class="headerlink" title="二、最小系统"></a><font size=3>二、最小系统</font></h1><p>单片机最小系统是指用最少的电路组成单片机可以工作的系统，通常最小系统包含： 电源电路、时钟电路、复位电路、 调试&#x2F;下载电路，对于STM32还需要启动选择电路。  </p>
<h2 id="1-电源电路"><a href="#1-电源电路" class="headerlink" title="1. 电源电路  "></a><font size=3>1. 电源电路  </font></h2><p>不同的MCU的工作电压可能是不一样的，比如51单片机通常为5V，而STM32单片机通常为3.3V。 因此，通常需要查阅该MCU的数据手册才能确定工作电压和规范。  </p>
<p>我们打开STM32F103xE数据手册（<a target="_blank" rel="noopener" href="https://www.st.com/resource/en/datasheet/stm32f103ze.pdf">Datasheet - STM32F103xC, STM32F103xD, STM32F103xE - High-density performance line Arm®-based 32-bit MCU with 256 to 512KB Flash, USB, CAN, 11 timers, 3 ADCs, 13 communication interfaces</a>） 找到“ 5.1.6 Power supply scheme ” 电源方案小结，可以看到如下图框图。  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417225559820.png" alt="image-20230417225559820" style="zoom:50%;" />

<p>根据数据手册的“ 5.3.1 General operating conditions”的表10 ，可得知上图中的各电压值大小。  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417225902352.png" alt="image-20230417225902352" style="zoom:50%;" />

<p>（1）VDD-VSS： 标准工作电压；电压范围： 2V<del>3.6V； 从VDD1 ~ VDD11， VSS1 ~ VSS11共有11组；需要11个100nF和1个4.7uF去耦电容； 经过MCU内部Regulator电源管理， 为CPU、 存储器等供电；<br>（2）VDDA-VSSA： 模拟工作电压；电压范围： 2V</del>3.6V(未使用ADC) 2.4V<del>3.6V(使用ADC)；需要1个10nF和1个1uF去耦电容； 由VDDA输入，为ADC、 DAC等供电；<br>（3）VREF+-VREF-： 基准参考电压；电压范围： 2.4V</del> VDDA； 可以使用独立参考电压VREF(需10nF+1uF高频滤波电容)， 也可使用VDDA输入，为ADC、 DAC等作基准参考电压；<br>（4）VBAT： RTC备用电源； 电压范围： 1.8V~ 3.6V； 通常使用纽扣电池外部供电，当主电源VDD掉电后，VBAT为实时时钟（ Real-Time Clock， RTC） 和备份寄存器供电（此时功耗超低） ；  </p>
<h2 id="2-时钟电路"><a href="#2-时钟电路" class="headerlink" title="2. 时钟电路  "></a><font size=3>2. 时钟电路  </font></h2><p>MCU是一个集成芯片， 由非常复杂的数字电路和其它电路组成， 需要稳定的时钟脉冲信号才能保证正常工作。 时钟如同人体内部的心脏一样，心脏跳动一下， 推动血液流动一下。时钟产生一次， 就推动处理器执行一下指令。除了CPU，芯片上所有的外设(GPIO、 I2C、 SPI等)都需要时钟，由此可见时钟的重要性。</p>
<p>芯片运行的时钟频率越高，芯片处理的速度越快，但同时功耗也越高。为了功耗和性能兼顾，微处理器一般有多个时钟源，同时还将时钟分频为多个大小，适配不同需求的外设。  </p>
<p>STM32的时钟树我们需要在STM32参考手册（<a target="_blank" rel="noopener" href="https://www.st.com/resource/en/reference_manual/rm0008-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf">STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx advanced Arm®-based 32-bit MCUs - Reference manual</a>）中查找，我们打开手册到 “ 7.2 Clocks ”，则有如下时钟树：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417230846857.png" alt="image-20230417230846857" style="zoom:40%;" />

<p>可以看到一共有四个时钟源：</p>
<p>（1）<strong>HSI</strong>(High Speed Internal clock signal)：</p>
<p>HSI是内部的高速时钟信号，频率8MHz。因为是内部提供，可以降低成本，缺点是精度较差。</p>
<p>（2）<strong>HSE</strong>(High Speed External clock signal):</p>
<p>HSE是外部的高速时钟信号，需要外部电路晶振，输入频率范围要求为4-16MHz。因为需要外部电路提供，成本会增加，但精度较好。</p>
<p>（3）<strong>LSE</strong>(Low Speed External clock signal):</p>
<p>LSE是外部的低速时钟信号，需要外部电路晶振，输入频率范围要求为32.768KHz。 一般用于RTC实时时钟。</p>
<p>（4）<strong>LSI</strong>(Low Speed Internal clock signal)：</p>
<p>LSI是内部的低速RC振荡器，频率40KHz。一般用于看门狗、 RTC实时时钟等。对于STM32F103系列的MCU， 都需要一个高速时钟和一个低速时钟，而这两个时钟可以选择使用内部时钟源节约成本，也可以选择外部时钟源输入提高精度。 如果使用内部时钟源，则无需设计外部电路，反之，则需要时钟电路。  </p>
<p>继续查看STM32数据手册的“ 5.3.6 External clock source characteristics ”，可以看到下图所示的外部时钟输入参考电路。</p>
<ul>
<li>HSE 典型应用(8MHz)</li>
</ul>
<p>对于HSE，当晶振为8MHz时， CL1和CL2的容值范围为5pF~25pF。 REXT用于产生负反馈，保证放大器工作在高增益的线性区， 同时也起到限流作用，通常在兆欧级，具体由晶振决定。  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417231317291.png" alt="image-20230417231317291" style="zoom:50%;" />

<ul>
<li>LSE 典型应用(32.768KHz)</li>
</ul>
<p>对于LSE，当晶振为32.768KHz时， CL1和CL2的容值范围为5pF~15pF。之所以选择32.768KHz，是因为<br>32768&#x3D;215， 分频设置寄存器通常为2n的形式，这样经过15次分频就很容易得到1Hz的频率。  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417231355101.png" alt="image-20230417231355101" style="zoom:50%;" />

<h2 id="3-复位电路"><a href="#3-复位电路" class="headerlink" title="3. 复位电路"></a><font size=3>3. 复位电路</font></h2><p>嵌入式系统中， 由于外界环境干扰， 难免出现程序跑飞或死机， 这时就需要复位让MCU重新运行。在打开STM32F103xE数据手册（<a target="_blank" rel="noopener" href="https://www.st.com/resource/en/datasheet/stm32f103ze.pdf">Datasheet - STM32F103xC, STM32F103xD, STM32F103xE - High-density performance line Arm®-based 32-bit MCU with 256 to 512KB Flash, USB, CAN, 11 timers, 3 ADCs, 13 communication interfaces</a>）中查找，我们打开手册到 “  5.3.15 NRST pin characteristics ”，则有如下复位电路：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417231603407.png" alt="image-20230417231603407" style="zoom:50%;" />

<p>该电路将一个按键接在了NRST引脚，一旦按键按下，NRST就会接地，拉低NRST，实现复位 。</p>
<h2 id="4-调试-下载电路"><a href="#4-调试-下载电路" class="headerlink" title="4. 调试&#x2F;下载电路"></a><font size=3>4. 调试&#x2F;下载电路</font></h2><p>不同的MCU，调试&#x2F;下载的方式可能不一样。比如51系列单片机，使用串口下载程序，同时也使用仿真调试。 对于STM32， 可以使用串口下载程序，也能使用串口打印进行简单调试，但STM32支持更高效的JTAG（ Joint Test Action Group） 调试接口和SWD（ Serial Wire Debug） 调试接口。  </p>
<p>STM32 的 JTAG 与 SWD 的接口共用， 如果下载器支持 SWD 调试模式， 则接上 JTAG 的时候同样可以使用 SWD模式。 常见的支持 SWD 模式的下载器有 JLINK V7&#x2F;V8 和 ST LINK 等。  </p>
<p>所涉及的引脚我们也可以查看STM32的参考手册（<a target="_blank" rel="noopener" href="https://www.st.com/resource/en/reference_manual/rm0008-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf">STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx advanced Arm®-based 32-bit MCUs - Reference manual</a>）的“ 9.3.5 JTAG&#x2F;SWD alternate function remapping ”一节：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417231931946.png" alt="image-20230417231931946" style="zoom:50%;" />

<p>关于更加详细的内容可以查看STM32参考手册（<a target="_blank" rel="noopener" href="https://www.st.com/resource/en/reference_manual/rm0008-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf">STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx advanced Arm®-based 32-bit MCUs - Reference manual</a>）的 “ 31 Debug support (DBG) ” 一节，有更为详细的说明。</p>
<p>一般设计原理图如下：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417232058730.png" alt="image-20230417232058730" style="zoom:50%;" />

<h3 id="4-1-JTAG协议简介"><a href="#4-1-JTAG协议简介" class="headerlink" title="4.1 JTAG协议简介"></a><font size=3>4.1 JTAG协议简介</font></h3><p>JTAG（Joint Test Action Group，联合测试行动小组）是一种国际标准测试协议（IEEE 1149.1兼容），主要用于芯片内部测试。可以对 FLASH<br>等器件进行程序的编程和烧写。 标准的 JTAG 接口是模式选择（TMS）、 时钟（TCK）、 数据输入（TDI）、 数据输出（TDO） 四线制接线。 它可以对多个串联在同一个接口上的器件分别进行测试。  现在多数的高级器件都支持JTAG协议，如ARM、DSP、FPGA器件等。相关JTAG引脚的定义为：</p>
<table>
<thead>
<tr>
<th align="center">引脚定义</th>
<th align="left">说明</th>
</tr>
</thead>
<tbody><tr>
<td align="center">TMS</td>
<td align="left">模式选择，TMS用来设置JTAG接口处于某种特定的测试模式；</td>
</tr>
<tr>
<td align="center">TCK</td>
<td align="left">时钟输入</td>
</tr>
<tr>
<td align="center">TDI</td>
<td align="left">数据输入，数据通过TDI引脚输入JTAG接口；</td>
</tr>
<tr>
<td align="center">TDO</td>
<td align="left">数据输出，数据通过TDO引脚从JTAG接口输出；</td>
</tr>
</tbody></table>
<h3 id="4-2-SWD协议简介"><a href="#4-2-SWD协议简介" class="headerlink" title="4.2 SWD协议简介"></a><font size=3>4.2 SWD协议简介</font></h3><p>串行调试（Serial Wire Debug），与 JTAG 相比，SWD只要两根线，分别为：SWCLK和SWDIO，减少了对单片机GPIO口的占用：</p>
<table>
<thead>
<tr>
<th align="center">引脚定义</th>
<th align="left">说明</th>
</tr>
</thead>
<tbody><tr>
<td align="center">SWDIO</td>
<td align="left">串行数据线，用于数据的读出和写入</td>
</tr>
<tr>
<td align="center">SWDCLK</td>
<td align="left">串行时钟线，提供所需要的时钟信号</td>
</tr>
</tbody></table>
<p>SWD 模式比 JTAG 在高速模式下面更加可靠。 在大数据量的情况下面 JTAG 下载程序会失败, 但是 SWD 发生的几率会小很多。基本使用 JTAG 仿真模式的情况下是可以直接使用 SWD 模式的, 只要仿真器（仿真器是啥？后边写STM32工具相关的时候会有笔记说明）支持。</p>
<h2 id="5-启动选择电路"><a href="#5-启动选择电路" class="headerlink" title="5. 启动选择电路  "></a><font size=3>5. 启动选择电路  </font></h2><p>不同的MCU， 启动的方式的种类可能不一样。比如51系列单片机， 只能从内置存储器读取数据启动，因此没有启动选择的必要。</p>
<p>对于STM32， 可以从内置存储器启动（默认） ，可以从系统存储器（用于从USART1下载程序），可以从内部SRAM启动（调电消失，可用于调试） ， 出现多个启动方式， 就需要启动选择。STM32通过BOOT1和BOOT2引脚的电平组合进行启动选择这一部分我们可以查看STM32的参考手册（<a target="_blank" rel="noopener" href="https://www.st.com/resource/en/reference_manual/rm0008-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf">STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx advanced Arm®-based 32-bit MCUs - Reference manual</a>）的“ 3.4 Boot configuration ”。</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230417232300976.png" alt="image-20230417232300976" style="zoom:50%;" />

<p>（1）BOO1为任意， BOOT0为0，开发板上电， MCU将从内部主存储器读取数据启动，是最常用的启动方式。  </p>
<p>（2）BOO1为0， BOOT1为1，开发板上电， MCU将从系统存储器读取数据启动， 在系统存储器里面厂家烧写的串口下载程序， 此时可以通过USART1烧写新程序到主存储器。  </p>
<p>（3）BOO1为1， BOOT1为1，开发板上电， MCU将直接从内部SRAM启动，SRAM的烧写次数寿命比Flash更多，可用于调试。  </p>
<p>通常，我们只使用主存储器启动即可。 从系统存储器启动，实现从串口下载程序也逐渐被淘汰， STM32的高端MCU已经不支持该方式下载。从SRAM启动也没什么必要，目前Flash的烧写寿命次数也远远超过用户实际烧写次数。  </p>
<h1 id="三、嵌入式C语言"><a href="#三、嵌入式C语言" class="headerlink" title="三、嵌入式C语言"></a><font size=3>三、嵌入式C语言</font></h1><p>其实之前就学习过C预言了，语法什么的在嵌入式中都是一模一样的，就是有些数据类型还有相关操作可以再熟悉一下。</p>
<h2 id="1-STM32支持的数据类型"><a href="#1-STM32支持的数据类型" class="headerlink" title="1. STM32支持的数据类型"></a><font size=3>1. STM32支持的数据类型</font></h2><p>以STM32F103ZE这一款芯片为例，这是一块32bit的MCU，基本数据类型在此款芯片中的数据长度，以及在HAL库函数中的定义（ stdint.h文件中的定义，采用C99标准）如下图：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230418221356751.png" alt="image-20230418221356751" style="zoom: 80%;" />

<p> 建议在开发过程中使用库定义的数据类型， 来定义变量或函数， 比如unsigned char a， 使用uint8_t a。  </p>
<h2 id="2-位运算"><a href="#2-位运算" class="headerlink" title="2. 位运算"></a><font size=3>2. 位运算</font></h2><h3 id="2-1-运算符"><a href="#2-1-运算符" class="headerlink" title="2.1 运算符"></a><font size=3>2.1 运算符</font></h3><p>这个操作我们在对STM32进行编程的时候会将常用到。位运算是指二进制位之间的运算。在嵌入式系统设计中， 常常要处理二进制的问题，例如将某个寄存器中的某一个位置1或者置0， 将数据左移5位等。常用的位运算符如表 下表：</p>
<table>
<thead>
<tr>
<th align="center">序号</th>
<th align="center">运算符</th>
<th align="left">含义</th>
<th align="center">序号</th>
<th align="center">运算符</th>
<th>含义</th>
</tr>
</thead>
<tbody><tr>
<td align="center">（1）</td>
<td align="center">&amp;</td>
<td align="left">按位与</td>
<td align="center">（2）</td>
<td align="center">|</td>
<td>按位或</td>
</tr>
<tr>
<td align="center">（3）</td>
<td align="center">~</td>
<td align="left">按位取反</td>
<td align="center">（4）</td>
<td align="center">&lt;&lt;</td>
<td>左移</td>
</tr>
<tr>
<td align="center">（5）</td>
<td align="center">&gt;&gt;</td>
<td align="left">右移</td>
<td align="center">（6）</td>
<td align="center">^</td>
<td>按位异或</td>
</tr>
</tbody></table>
<ul>
<li>（1）按位与运算符（ &amp; ）</li>
</ul>
<p>参与运算的两个操作数，每个二进制位进行“与” 运算，若两个都为1，结果为1，否者为0。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1011</span> &amp; <span class="number">1001</span> = <span class="number">1001</span></span><br></pre></td></tr></table></figure>

<p>第一位都为1，结果为1；第二位都为0，结果为0；第三位一个为1，一个为0，结果为0；第四位都为1，结果为1。 最后结果为1001。  </p>
<ul>
<li>（2）按位或运算符（ | ）</li>
</ul>
<p>参与运算的两个操作数，每个二进制位进行“ 或”运算，若两个都为0，结果为1，否者为1。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1011</span> | <span class="number">1001</span> = <span class="number">1011</span></span><br></pre></td></tr></table></figure>

<p>第一位都为1，结果为1；第二位都为0，结果为0；第三位一个为1，一个为0，结果为1；第四位都为1，结果为1。最后结果为1011。  </p>
<ul>
<li>（3）按位取反运算符（ ~ ）</li>
</ul>
<p>按位取反运算符用于对一个二进制数按位取反。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~<span class="number">1011</span> = <span class="number">0100</span></span><br></pre></td></tr></table></figure>

<p>第一位为1， 取反为0；第二位为0， 取反为1；第三位为1， 取反为0，结果为1；第四位为1， 取反为0。最后结果为0100。  </p>
<ul>
<li>（4）（5）左移（ &lt;&lt; ）和右移（ &gt;&gt; ） 运算符</li>
</ul>
<p>左移（ &lt;&lt; ）运算符用于将一个数左移若干位，右移（ &gt;&gt; ）运算符用于将一个数右移若干位。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">unsigned</span> <span class="type">char</span> val = <span class="number">1011</span> <span class="number">1001</span></span><br><span class="line">val &lt;&lt; <span class="number">3</span> = <span class="number">1011</span> <span class="number">1001</span> &lt;&lt; <span class="number">3</span> = <span class="number">1100</span> <span class="number">1000</span></span><br><span class="line">val &gt;&gt; <span class="number">3</span> = <span class="number">1011</span> <span class="number">1001</span> &gt;&gt; <span class="number">3</span> = <span class="number">0001</span> <span class="number">0111</span></span><br></pre></td></tr></table></figure>

<p>若val&#x3D;val&lt;&lt;3，表示val左移3位，然后赋值给val，左移过程中，高位移出去后被丢弃， 低位补0，最后val结果为11001000；若val&#x3D;val&gt;&gt;3，表示val右移3位，然后赋值给val， 右移过程中， 低位移出去后被丢弃， 高位补0，最后val结果为00010111。  </p>
<ul>
<li>（6）按位异或运算符</li>
</ul>
<p>简单来说就是相同为1不同为0，经过三次异或可以交换两个数的值。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">a = <span class="number">0x3</span> = <span class="number">0011</span></span><br><span class="line">b = <span class="number">0x5</span> = <span class="number">0110</span></span><br><span class="line">    </span><br><span class="line">a = a ^ b = <span class="number">0011</span> ^ <span class="number">0110</span> = <span class="number">1010</span> = <span class="number">0xa</span>;</span><br><span class="line">b = a ^ b = <span class="number">1010</span> ^ <span class="number">0110</span> = <span class="number">0011</span> = <span class="number">0x3</span>;</span><br><span class="line">a = a ^ b = <span class="number">1010</span> ^ <span class="number">0011</span> = <span class="number">0110</span> = <span class="number">0x5</span>;</span><br></pre></td></tr></table></figure>

<h3 id="2-2-清0或置1"><a href="#2-2-清0或置1" class="headerlink" title="2.2 清0或置1"></a><font size=3>2.2 清0或置1</font></h3><p>在嵌入式中，经常使用位运算符实现清0或置1。  </p>
<p>例如， MCU的ODR寄存器控制引脚的输出电平高低，寄存器为32位， 每位控制一个引脚的电平。假设需要控制GPIOB的1号引脚输出电平的高低，设置该寄存器第0位为1，输出高电平，设置该寄存器第0位为0，输出低电平。  </p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOB_ODR (*(volatile unsigned int *)(0x40010C0C))</span></span><br><span class="line">GPIOB_ODR &amp;= ~(<span class="number">1</span>&lt;&lt;<span class="number">0</span>);</span><br><span class="line">GPIOB_ODR |= (<span class="number">1</span>&lt;&lt;<span class="number">0</span>);</span><br></pre></td></tr></table></figure>

<p>第1行： 使用#define定义了GPIOB_ODR 对应的内存地址为0x40010C0C。 该地址为MCU的ODR寄存器地址。</p>
<p>第2行： GPIOB_ODR &amp;&#x3D; <del>(1&lt;&lt;0)实际是GPIOB_ODR &#x3D; GPIOB_ODR &amp; ~(1&lt;&lt;0)， 先将GPIOB_ODR和</del>(1&lt;&lt;0)的进行与运算，运算结果赋值给GPIOB_ODR。 1&lt;&lt;0 的值为 00000000 00000000 00000000 00000001，<br>再取反为11111111 11111111 11111111 11111110， 则GPIO_ODR的第0位和0与运算， 结果必为0，其它位和1<br>运算，由GPIO_ODR原来的值决定结果。这就实现了，只将GPIO_ODR的第0位清0，其它位保持不变的效果，实现了单独控制对应引脚电平输出低。</p>
<p>第3行： GPIOB_ODR |&#x3D; (1&lt;&lt;0)实际是GPIOB_ODR &#x3D; GPIOB_ODR | (1&lt;&lt;0)，先将GPIOB_ODR和(1&lt;&lt;0)的进行或运算，运算结果赋值给GPIOB_ODR。 1&lt;&lt;0的值为00000000 00000000 00000000 00000001，则GPIO_ODR的第0位和0或运算，结果必为1，其它位和0运算，由GPIO_ODR原来的值决定结果。这就实现了，只将GPIO_ODR的第0位置1，其它位保持不变的效果，实现了单独控制对应引脚电平输出高。  </p>
<h2 id="3-非的使用"><a href="#3-非的使用" class="headerlink" title="3. 非的使用"></a><font size=3>3. 非的使用</font></h2><p>这个我们在编程的过程中也经常用到，非的结果只有两种，就是0和非0.</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">!<span class="number">0</span>   ==&gt; <span class="number">1</span></span><br><span class="line">!<span class="number">1</span>   ==&gt; <span class="number">0</span></span><br><span class="line">!<span class="number">100</span> ==&gt; <span class="number">0</span></span><br></pre></td></tr></table></figure>

<h2 id="4-weak与-attribute-weak"><a href="#4-weak与-attribute-weak" class="headerlink" title="4. __weak与__attribute__((weak))"></a><font size=3>4. __weak与__attribute__((weak))</font></h2><p>为什么要了解这个？因为后边要用HAL库进行开发，HAL库里边好多好多这种符号，这里还是要了解一下的。前边学习C语言的时候，有专门学习过 __attribute__，具体可以看《LV01-17-C语言-attribute机制》。注意这一小节的笔记是后边补充过来的，由于MDK可以很好的看到代码生成的汇编，调试的时候可以看到代码和汇编的对应关系，所以这里用了后边创建的HAL库空工程。注意把工程的调试方式改成软件仿真，不改好像也没啥问题，不影响：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230501164207687.png" alt="image-20230501164207687" style="zoom:50%;" />

<h3 id="4-1-两者关系"><a href="#4-1-两者关系" class="headerlink" title="4.1 两者关系"></a><font size=3>4.1 两者关系</font></h3><p>GNU 的编译器（gcc）扩展了一个关键字 __attribute__，通过该关键字，用户可以在声明时指定特殊的属性，使用时该关键字后跟双括号内的属性，例如：__attribute__((属性名字))。属性名字都是定义好的，weak 属性就是其中之一：__attribute__((weak))。</p>
<p>在 ARM 编译器（armcc）中，支持和 GCC 相同的关键字 __attribute__，使用方式也基本相同，如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">__attribute__((attribute1, attribute2, ...))            <span class="comment">// 例如：void * Function_Attributes_malloc_0(int b) __attribute__((malloc));</span></span><br><span class="line">__attribute__((__attribute1__, __attribute2__, ...))    <span class="comment">// 例如：static int b __attribute__((__unused__));</span></span><br></pre></td></tr></table></figure>

<p>除此之外，ARM 编译器（armcc）还扩展了一个关键字 __weak，例如：__weak void f(void); 或者 __weak int i;。ARM 的汇编器（armasm）以另一种方式 [WEAK] 支持该特性。在许多源码中，经常通过宏定义的形式来定义关键字，例如 上面linux 中的 __weak 就是 宏定义的 __attribute__((weak))</p>
<h3 id="4-2-强弱符号"><a href="#4-2-强弱符号" class="headerlink" title="4.2 强弱符号"></a><font size=3>4.2 强弱符号</font></h3><p>在 GCC 中，被 __attribute__((weak)) 修饰的符号，称之为 弱符号（Weak Symbol）。例如：弱函数、弱变量；没有 __attribute__((weak)) 修饰的符号被称为强符号。在 ARM 中，没有弱符号和强符号这种叫法，只有个弱引用（Weak References） 和 非弱引用（non-weak reference ） 、 弱定义（Weak definitions） 和 非弱定义（non-weak definition）。需要注意的是编译器和汇编器都可以输出弱符号。</p>
<ul>
<li>非弱引用</li>
</ul>
<p>非弱引用就是我们平常使用的对于非弱函数或者弱变量的引用。如果链接器无法在到目前为止已加载内容中解析对正常非弱符号的引用问题，则 它会尝试通过在库中找到符号 来解决此问题：如果找不到此类引用，则链接器将报告错误。如果解析了这样的引用，则从入口点可以通过至少一个非弱引用来访问的节区被标记为已使用。这样可以确保链接器不会将该节作为未使用的节删除。 每个非弱引用都必须通过一个定义来解决。 如果有多个定义，则链接器将报告错误。</p>
<ul>
<li>弱引用</li>
</ul>
<p>引用弱声明的函数或者变量的引用即为弱引用。 链接器不会从库中加载对象来解析弱引用。仅当由于其他原因在镜像中包含了定义时，它才能解析弱引用。弱引用不会导致链接器将包含定义的节区标记为已使用，因此链接器可能会将其标记为未使用而删除。</p>
<h3 id="4-3-weak可以用在哪？"><a href="#4-3-weak可以用在哪？" class="headerlink" title="4.3 __weak可以用在哪？"></a><font size=3>4.3 __weak可以用在哪？</font></h3><p>__weak 关键字可以应用于函数和变量的声明以及函数定义。</p>
<h4 id="4-3-1-声明"><a href="#4-3-1-声明" class="headerlink" title="4.3.1 声明"></a><font size=3>4.3.1 声明</font></h4><p>__weak 可以用于函数声明或者变量的声明。对于声明，此存储类指定一个 extern 对象声明，即使该对象不存在，对于该声明的引用也不会导致链接器对未解析的引用（找不到定义的引用）当做错误来处理。</p>
<p>如果在当前编译单元中可以找到 __weak 声明定义，则会用找到的定义替换 __weak 引用；对于找不到定义 __weak 的声明（函数或变量），编译器做如下处理：</p>
<ul>
<li><p>引用被解析为分支连接指令 BL，找不到定义 __weak 的声明（函数或变量）等效于将被引用的分支为 NOP。</p>
</li>
<li><p>最后直接将引用替换为 NOP 指令。</p>
</li>
</ul>
<p>注意：必须是在当前编译单元，不再当前编译单元的没有意义（例如 func1 在 main.c 中只有__weak 声明，但是没有定义）。具体看下图的测试代码（这里）：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230501170931048.png" alt="image-20230501170931048" style="zoom:50%;" />

<p>如上图所示，func1使用了__weak定义，也使用了__weak声明，并且在 main.c 中重写了，相当于在main.c中重新进行了定义，那么就会用重新进行的定义来替换__weak引用，所以引用被解析为BL，被引用分支就是func2函数，所以最终会跳转到main.c中定义的func2函数执行，，而func1并未使用__weak定义，但是月使用了__weak声明，然后在main.c中也并未重定义，所以直接被替换为NOP了。</p>
<p>【注意】我经过测试得出的结论（MDK v5.29.0）：</p>
<p>（1）__weak声明函数，若定义时使用了__weak来修饰，那么这个函数就是一个弱函数，可以被重写，并且实际运行时不会被调用；但是定义时若是没有使用__weak，此时函数会被识别为弱函数，但是，无法重写，重写的话会报重定义错误，并且实际运行时也不会被运行。</p>
<p>（2）__weak定义函数，若使用__weak来修饰声明函数，那么这个函数就是一个弱函数，可以被重写，实际运行时此弱函数不会被调用；若是没有使用__weak来修饰声明函数，那么这个函数会被识别成非弱函数，但是，此函数依然可以重写，若是重写了这个函数，具体最终调用的我测过了，是重写的那一部分代码，若是没有重写，那么就会调用__weak定义的那一部分代码。</p>
<h4 id="4-3-2-定义"><a href="#4-3-2-定义" class="headerlink" title="4.3.2 定义"></a><font size=3>4.3.2 定义</font></h4><p>用 __weak 定义的函数弱输出其符号。弱定义的函数的行为类似于正常定义的函数，除非将同名的非弱定义的函数链接到同一镜像中。 如果在同一镜像中同时存在非弱定义函数和弱定义函数，则对该函数的所有调用都会解析为调用非弱函数，否则直接使用弱定义的函数（与上面的若声明不同）。</p>
<p>上边什么意思呢？简单来说意思就是，我们的工程中，存在一个弱定义函数，我们要是没有重定义这个函数，那么链接的时候会使用弱定义的函数，若是重写了弱定义的函数，那么我们重写的非弱定义函数就会覆盖掉弱定义的函数，HAL库中，我们重写一些函数也是这个道理。</p>
<p>如果想要使用多个弱定义，则除非使用链接器选项 –muldefweak，否则链接器会生成一条错误消息。在这种情况下，链接器随机选择一个供所有调用来使用。使用方式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//=============================================</span></span><br><span class="line"><span class="comment">/* weak_test.h ！！！注意所在文件不同！！！ */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">func1</span><span class="params">(<span class="type">void</span>)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">func2</span><span class="params">(<span class="type">void</span>)</span>;</span><br><span class="line"><span class="comment">//=============================================</span></span><br><span class="line"><span class="comment">/* weak_test.c ！！！注意所在文件不同！！！ */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">func1</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    func2();        <span class="comment">/* 这里将替换为 main.c 中的 func2 */</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">__weak <span class="type">void</span> <span class="title function_">func2</span><span class="params">(<span class="type">void</span>)</span>     <span class="comment">/* 弱定义 */</span></span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//=============================================</span></span><br><span class="line"><span class="comment">/* main.c ！！！注意所在文件不同！！！ */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">func2</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span> <span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">	func2();</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h3 id="4-4-weak使用的限制"><a href="#4-4-weak使用的限制" class="headerlink" title="4.4 __weak使用的限制"></a><font size=3>4.4 __weak使用的限制</font></h3><p>（1）函数或变量不能在同一编译中同时弱和非弱地使用。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">func</span><span class="params">(<span class="type">void</span>)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">g</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    func();    <span class="comment">/* 非弱函数引用 */</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">__weak <span class="type">void</span> <span class="title function_">func</span><span class="params">(<span class="type">void</span>)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">h</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    func();    <span class="comment">/* 弱函数引用 */</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>（2）不能在定义函数或变量的同一编译中使用弱函数或弱变量，如下将导致编译错误（正确的使用方式参考上面的使用示例）</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* weak_test.c 如下同一文件中的定义及使用将报错 */</span></span><br><span class="line">__weak <span class="type">void</span> <span class="title function_">func</span><span class="params">(<span class="type">void</span>)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">h</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line">    func();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">func</span><span class="params">()</span></span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>（3）弱函数不能是内联函数</p>
<h3 id="4-5-attribute-weak-用在哪？"><a href="#4-5-attribute-weak-用在哪？" class="headerlink" title="4.5 __attribute__((weak))用在哪？"></a><font size=3>4.5 __attribute__((weak))用在哪？</font></h3><p>__attribute__关键字使您可以指定变量或结构字段，函数和类型的特殊属性（与具体属性）。该关键字的作用与 __weak 的作用基本是一样的，在使用时有些不同，此外在某些情况下，编译的处理也有些区别。</p>
<h4 id="4-5-1-声明"><a href="#4-5-1-声明" class="headerlink" title="4.5.1 声明"></a><font size=3>4.5.1 声明</font></h4><p>这个参数是 GUN 编译器的一个扩展，ARM 编译器也支持该关键字。__attribute__((weak)) 可以声明弱变量，并且其声明方式与 __weak 相比更加灵活。除了 __weak 的声明方式，我们还可以用 </p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">extern</span> <span class="type">int</span> Variable_Attributes_weak_1 __attribute__((weak));</span><br></pre></td></tr></table></figure>

<p>__attribute__((weak)) 可以声明弱函数，其声明方式与 __weak 相比更加灵活。除了 __weak 的声明方式，我们还可以用:</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">extern</span> <span class="type">int</span> <span class="title function_">Function_Attributes_weak_0</span> <span class="params">(<span class="type">int</span> b)</span> __<span class="title function_">attribute__</span><span class="params">((weak))</span>;</span><br></pre></td></tr></table></figure>

<p>任何包含了 __attribute__((weak)); 声明的文件的中的同名函数定义，都将被当做弱函数。</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230501174643348.png" alt="image-20230501174643348" style="zoom: 33%;" />

<h4 id="4-5-2-定义"><a href="#4-5-2-定义" class="headerlink" title="4.5.2 定义"></a><font size=3>4.5.2 定义</font></h4><p>用 __attribute__((weak))定义的函数弱输出其符号（与 __weak相同）。其使用方式有以下两种：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">__attribute__((weak)) <span class="type">void</span> <span class="title function_">func1</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Weak func1!\r\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/* 或者 */</span></span><br><span class="line"><span class="type">void</span> __attribute__((weak)) func1(<span class="type">void</span>)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Weak func1!\r\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h3 id="4-6-两者的区别"><a href="#4-6-两者的区别" class="headerlink" title="4.6 两者的区别"></a><font size=3>4.6 两者的区别</font></h3><p>网上找到的区别如下，<strong>但是我对这两个区别持怀疑态度</strong>，因为在前边__weak的声明一小节的例子中，显然使用func1并未使用__weak定义，但是使用了__weak来声明，最终也被识别为弱函数了：</p>
<p>（1）__weak 和 __attribute__((weak)) 在声明和定义的时候，其所处的位置有不同。</p>
<p>（2）__weak 仅在函数定义中使用时才会生成弱函数。而在任何情况下（声明和定义） __attribute__((weak)) 都会生成弱函数，无论是用于函数定义还是用于函数声明中！</p>
<h1 id="四、STM32开发"><a href="#四、STM32开发" class="headerlink" title="四、STM32开发"></a><font size=3>四、STM32开发</font></h1><h2 id="1-开发方式"><a href="#1-开发方式" class="headerlink" title="1. 开发方式"></a><font size=3>1. 开发方式</font></h2><p>这篇笔记是已经对STM32有了一定的了解后才写的，其实STM32的开发大概有四种方式</p>
<ul>
<li>（1）汇编，强的一批，我们可以直接使用内部寄存器和STM32的寄存器来使用汇编开发，难度可想而知。</li>
<li>（2）C语言+寄存器开发，这种相对容易，毕竟C语言我们都学过，无非是寄存器超级多。</li>
<li>（3）C语言+标准库，这个是我入门STM32的时候最先使用的库，一般都用这个。</li>
<li>（4）C语言+HAL库，HAL库配合STM32CubeMX软件使用，由于图形化的配置界面，这个HAL库据说是ST以后主推的库。</li>
</ul>
<h2 id="2-库开发与寄存器开发的关系"><a href="#2-库开发与寄存器开发的关系" class="headerlink" title="2. 库开发与寄存器开发的关系  "></a><font size=3>2. 库开发与寄存器开发的关系  </font></h2><p>一般我们都是从学 51 单片机开发转而学习 STM32 开发，习惯了 51 单片机的寄存器开发方式，突然一个 ST 官方库摆在面前会一头雾水，不知道从何下手。</p>
<p>下那么STM32 固件库到底是什么，和寄存器开发有什么关系？其实一句话就可以概括：固件库就是函数的集合，固件库函数的作用是向下负责与寄存器直接打交道，向上提供用户函数调用的接口（API）。  </p>
<p>在 51 的开发中我们常常的作法是直接操作寄存器，比如要控制某些 IO 口的状态，我们直接操作寄存器：  </p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">P0 = <span class="number">0x11</span>;</span><br></pre></td></tr></table></figure>

<p>而在 STM32 的开发中，我们同样可以操作寄存器：  </p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GPIOx-&gt;BRR = <span class="number">0x0011</span>;</span><br></pre></td></tr></table></figure>

<p>这种方法当然可以，但是这种方法的劣势是我们需要去掌握每个寄存器的用法，才能正确使用STM32，而对于 STM32 这种级别的 MCU，数百个寄存器记起来又是谈何容易。于是 ST(意法半导体)推出了官方固件库，固件库将这些寄存器底层操作都封装起来，提供一整套接口（API）供开发者调用，大多数场合下，我们不需要去知道操作的是哪个寄存器，我们只需要知道调用哪些函数即可 ，比如上面的控制 BRR 寄存器实现电平控制，官方库封装了一个函数：  </p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">GPIO_ResetBits</span><span class="params">(GPIO_TypeDef* GPIOx, <span class="type">uint16_t</span> GPIO_Pin)</span></span><br><span class="line">&#123;</span><br><span class="line">	GPIOx-&gt;BRR = GPIO_Pin;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这个时候我们不需要再直接去操作 BRR 寄存器了，只需要知道怎么使用 GPIO_ResetBits()这个函数就可以了。 在对外设的工作原理有一定的了解之后，再去看固件库函数，基本上函数名字能告诉我们这个函数的功能是什么，该怎么使用， 这样是不是开发会方便很多？</p>
<p>任何处理器，不管它有多么的高级，归根结底都是要对处理器的寄存器进行操作。但是固件库不是万能的，如果想要把 STM32 学透， 光读 STM32 固件库是远远不够的。还是要了解一下 STM32 的原理，而这些原理了解了，在进行固件库开发过程中才可能得心应手游刃有余。  </p>
<p>库函数的引入，大大降低了 STM 主控芯片开发的难度。 ST 公司为了方便用户开发 STM32芯片开发提供了三种库函数，从时间产生顺序是：标准库、 HAL 库和 LL 库。目前 ST 已经逐渐暂停对部分标准库的支持， ST 的库函数维护重点对象已经转移到 HAL 库和 LL 库上。 </p>
<h2 id="3-STM32-固件库与-CMSIS-标准"><a href="#3-STM32-固件库与-CMSIS-标准" class="headerlink" title="3. STM32 固件库与 CMSIS 标准"></a><font size=3>3. STM32 固件库与 CMSIS 标准</font></h2><h3 id="3-1-CMSIS的来历"><a href="#3-1-CMSIS的来历" class="headerlink" title="3.1  CMSIS的来历"></a><font size=3>3.1  CMSIS的来历</font></h3><p>STM32 固件库就是函数的集合，那么对这些函数有什么要求呢？这里就涉及到一个 CMSIS 标准的基础知识，这部分知识可以从《Cortex-M3 权威指南》中了解到，这里大概提一下。</p>
<p> STM32 和 ARM 以及 ARM7是什么关系？其实 ARM 是一个做芯片标准的公司，它负责的是芯片内核的架构设计，而 TI， ST 这样的公司，他们并不做标准，他们是芯片公司，他们是根据 ARM 公司提供的芯片内核标准设计自己的芯片。所以，任何一个做 Cortex-M3 芯片，他们的内核结构都是一样的，不同的是他们的存储器容量， 片上外设， IO 以及其他模块的区别。所以我们会发现，不同公司设计的 Cortex-M3 芯片他们的端口数量，串口数量，控制方法这些都是有区别的， 这些资源他们可以根据自己的需求理念来设计。同一家公司设计的多种 Cortex-m3 内核芯片的片上外设也会有很大的区别，比如 STM32F103RBT 和 STM32F103ZET，他们的片上外设就有很大的区别。我们可以通过《Cortex-M3 权威指南》中的一个图来了解一下：  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420231930503.png" alt="image-20230420231930503" style="zoom: 80%;" />

<p>从上图可以看出，芯片虽然是芯片公司设计，但是内核却要服从 ARM 公司提出的 Cortex-M3内核标准了，理所当然，芯片公司每卖出一片芯片，需要向 ARM 公司交一定的专利费。既然大家都使用的是 Cortex-M3 核，也就是说，本质上大家都是一样的，这样 ARM 公司为了能让不同的芯片公司生产的 Cortex-M3 芯片能在软件上基本兼容，和芯片生产商共同提出了一套标准 CMSIS 标准(Cortex Microcontroller Software Interface Standard) ,翻译过来是“ARM Cortex™ 微控制器软件接口标准”。 ST 官方库就是根据这套标准设计的。这里我们来看看基于 CMSIS 应用程序基本结构：  </p>
<p><img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420232215474.png" alt="image-20230420232215474"></p>
<p>CMSIS 分为 3 个基本功能层：</p>
<p>（1）核内外设访问层： ARM 公司提供的访问，定义处理器内部寄存器地址以及功能函数。</p>
<p>（2）中间件访问层:定义访问中间件的通用 API,也是 ARM 公司提供。</p>
<p>（3）外设访问层：定义硬件寄存器的地址以及外设的访问函数。</p>
<p>从图中可以看出， CMSIS 层在整个系统中是处于中间层，向下负责与内核和各个外设直接打交道，向上提供实时操作系统用户程序调用的函数接口。如果没有 CMSIS 标准，那么各个芯片公司就会设计自己喜欢的风格的库函数，而 CMSIS 标准就是要强制规定，芯片生产公司设计的库函数必须按照 CMSIS 这套规范来设计。</p>
<h3 id="3-2-CMSIS-标准"><a href="#3-2-CMSIS-标准" class="headerlink" title="3.2 CMSIS 标准  "></a><font size=3>3.2 CMSIS 标准  </font></h3><p>根据一些调查研究表明， 软件开发已经被嵌入式行业公认为最主要的开发成本,为了降低这个成本， ARM 与 Atmel、 IAR、 KEIL、 SEGGER 和 ST 等诸多芯片和软件工具厂商合作， 制定了一个将所有 Cortex 芯片厂商的产品的软件接口标准化的标准 CMSIS（Cortex Microcontroller Software Interface Standard）。下面来看 ARM 官方提供的 CMSIS 规范架构， 如图 ：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113112812542.png" alt="image-20240113112812542" />

<p>从图中可以看出这个标准分级明显， 从用户程序到内核底层实现做了分层。按照这个分级，HAL 库属于 CMSIS-Pack 中的“Peripheral HAL”层。CMSIS 规定的最主要的 3 个部分为：核内外设访问层（由 ARM 负责实现）、 片上外设访问层和外设访问函数（后面两个由芯片厂商负责实现）。ARM 整合并提供了大量的模版，各厂商根据自己的芯片差异修改模版， 这其中包括汇编文件 startup_device.s、 system_.h 和 system_.c 这些与初始化和系统相关的函数。  </p>
<p>结合 STM32F1 的芯片来说，其 CMSIS 应用程序的简单结构框图，不包括实时操作系统和中间设备等组件，CMSIS 分级下的 stm32f1 的文件分布  结构如图 :</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113113102109.png" alt="image-20240113113102109" style="zoom:64%;" />



<p>一个简单的例子，我们在使用 STM32 芯片的时候首先要进行系统初始化， CMSIS 规范就规定， 系统初始化函数名字必须为 SystemInit，所以各个芯片公<br>司写自己的库函数的时候就必须用 SystemInit 对系统进行初始化。 CMSIS 还对各个外设驱动文件的文件名字规范化，以及函数名字规范化等等一系列规定。上一节讲的函数GPIO_ResetBits 这个函数名字也是不能随便定义的，是要遵循 CMSIS 规范的。至于 CMSIS 的具体内容就不多说了，网上资料很多。</p>
<h2 id="4-三种官方库"><a href="#4-三种官方库" class="headerlink" title="4. 三种官方库"></a><font size=3>4. 三种官方库</font></h2><p>ST 先后提供了两套固件库：<strong>标准库和 HAL 库</strong>。 </p>
<p>STM32 芯片面市之初只提供了丰富全面的标准库，大大便利了用户程序开发，为广大开发板所推崇，同时也为 ST 积累了大量标准库用户。</p>
<p>大约到 2014 年左右， ST 在标准库的基础上又推出了 HAL 库。实际上， HAL 库和标准库本质上是一样的，都是提供底层硬件操作 API，而且在使用上也是大同小异。</p>
<p>据说 ST 官方之所以这几年大力推广 HAL 库，是因为 HAL 的结构更加容易整合 STM32Cube，而 STM32CubeMX 是 ST 这几年极力推荐的程序生成开发工具。所以后来新出的 STM32 芯片， ST 直接只提供 HAL 库。</p>
<p>那么是使用 HAL 库还是标准库好呢？其实 HAL库和标准库都非常强大，对于目前标准库支持的芯片采用标准库开发也非常方便实用。不需要纠结自己学的是 HAL 库还是标准库，无论使用哪种库，只要理解了 STM32 本质，任何库都是一种工具，使用起来都非常方便。学会了一种库，另外一种库也非常容易上手，程序开发思路转变也非常容易。  </p>
<h3 id="4-1-标准外设库"><a href="#4-1-标准外设库" class="headerlink" title="4.1 标准外设库"></a><font size=3>4.1 标准外设库</font></h3><p>标准外设库（Standard Peripherals Library）是对 STM32 芯片的一个完整的封装，包括所有标准器件外设的器件驱动器， 是 ST 最早推出的针对 STM 系列主控的库函数。标准库的设计的初衷是减少用户的程序编写时间，进而降低开发成本。几乎全部使用 C 语言实现并严格按照“Strict ANSI-C”、 MISRA-C 2004 等多个 C 语言标准编写。但标准外设库仍然接近于寄存器操作，主要就是将一些基本的寄存器操作封装成了 C 函数。开发者仍需要关注所使用的外设是在哪个总线之上，具体寄存器的配置等底层信息。  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113113729681.png" alt="image-20240113113729681" style="zoom:50%;" />

<p>ST 为各系列提供的标准外设库稍微有些区别。例如， STM32F1x 的库和 STM32F3x 的库在文件结构上就有些不同，此外，在内部的实现上也稍微有些区别，这个在具体使用（移植）时，需要注意一下！但是，不同系列之间的差别并不是很大，而且在设计上是相同的。 STM32 的标准外设库涵盖以下 3 个抽象级别：</p>
<ul>
<li><p>包含位域和寄存器在内的完整的寄存器地址映射</p>
</li>
<li><p>涵盖所有外围功能（具有公共 API 的驱动器）的例程和数据结构的集合。</p>
</li>
<li><p>一组包含所有可用外设的示例，其中包含最常用的开发工具的模板项目。</p>
</li>
</ul>
<p>关于更详细的信息，可以参考 ST 的官方文档《STM32 固件库使用手册中文翻译版》，文档中对于标准外设库函数命名、文件结构等都有详细的说明， 这里就不多介绍了。值得一提的是由于 STM32 的产品性能及标准库代码的规范和易读性以及例程的全覆盖性，使 STM32 的开发难度大大下降。 但 ST 从 L1 以后的芯片 L0、 L4 和 F7 等系列就没有再推出相应的标准库支持包了。  </p>
<h4 id="4-1-1-文件下载"><a href="#4-1-1-文件下载" class="headerlink" title="4.1.1 文件下载"></a><font size=3>4.1.1 文件下载</font></h4><p>我们下载一个标准库，我们来这个STM32标准外设库下载：<a target="_blank" rel="noopener" href="https://www.st.com/zh/embedded-software/stm32-standard-peripheral-libraries.html">STM32标准外设软件库 - 意法半导体STMicroelectronics</a></p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230420233318141.png" alt="image-20230420233318141" style="zoom:25%;" />

<h4 id="4-1-2-标准库介绍"><a href="#4-1-2-标准库介绍" class="headerlink" title="4.1.2 标准库介绍"></a><font size=3>4.1.2 标准库介绍</font></h4><p>接下来我们来看一下目录结构，前面我们下载完解压，大概的目录结构如下所示：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230421193945130.png" alt="image-20230421193945130" style="zoom:50%;" />

<p>（1）Libraries 文件夹下面有 CMSIS 和 STM32F10x_StdPeriph_Driver 两个目录，这两个目录包含固件库核心的所有子文件夹和文件。其中CMSIS目录下面是启动文件 ，STM32F10x_StdPeriph_Driver 放的是 STM32 固件库源码文件。源文件目录下面的 inc 目录存放的是 stm32f10x_xxx.h 头文件,无需改动。 src 目录下面放的是 stm32f10x_xxx.c 格式的固件库源码文件。每一个.c 文件和一个相应的.h 文件对应。这里的文件也是固件库的核心文件，每个外设对应一组文件。Libraries 文件夹里面的文件在我们建立工程的时候都会使用到。</p>
<p>（2）Project 文件夹下面有两个文件夹。顾名思义， STM32F10x_StdPeriph_Examples 文件夹下面存放的 ST 官方提供的固件实例源码，在以后的开发过程中，可以参考修改这个官方提供的实例来快速驱动自己的外设，很多开发板的实例都参考了官方提供的例程源码。 STM32F10x_StdPeriph_Template 文件夹下面存放的是工程模板。</p>
<p>（3）Utilities 文件下就是官方评估板的一些对应源码，这个可以忽略不看。</p>
<p>（4）根目录中还有一个 stm32f10x_stdperiph_lib_um.chm 文件，直接打开可以知道，这是一个固件库的帮助文档，这个文档非常有用，只可惜是英文的，在开发过程中，这个文档会经常被使用到。  </p>
<h4 id="4-1-3-关键文件介绍"><a href="#4-1-3-关键文件介绍" class="headerlink" title="4.1.3 关键文件介绍"></a><font size=3>4.1.3 关键文件介绍</font></h4><p>主要是Libraries 目录下面几个重要的文件：</p>
<ul>
<li>CoreSupport 目录</li>
</ul>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230421194328019.png" alt="image-20230421194328019" style="zoom: 50%;" />

<p>core_cm3.c 和 core_cm3.h 文件位于Libraries\CMSIS\CM3\CoreSupport 目录下面的，这个就是 CMSIS 核心文件，提供进入 M3 内核接口，这是 ARM 公司提供，对所有 CM3 内核的芯片都一样。我们永远都不需要修改这个文件。  </p>
<ul>
<li>DeviceSupport目录</li>
</ul>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230421194453728.png" alt="image-20230421194453728" style="zoom: 40%;" />

<p>这个目录下面有三个文件： system_stm32f10x.c, system_stm32f10x.h 以及 stm32f10x.h 文件。</p>
<p>（1）system_stm32f10x.c 和对应的头文件 system_stm32f10x.h 文件的功能是设置系统以及总线时钟，这个里面有一个非常重要的 SystemInit()函数，这个函数在我们系统启动的时候都会调用，用来设置系统的整个时钟系统。 </p>
<p>（2）stm32f10x.h 这个文件就相当重要了，只要做 STM32 开发，几乎时刻都要查看这个文件相关的定义。这个文件打开可以看到，里面非常多的结构体以及宏定义。 这个文件里面主要是系统寄存器定义申明以及包装内存操作， 对于这里是怎样申明以及怎样将内存操作封装起来的。 </p>
<p>（3） DeviceSupport\ST\STM32F10x 同一级还有一个 startup 文件夹，这个文件夹里面放的文件是启动文件。在\startup\arm 目录下，我们可以看到 8 个 startup 开头的.s 文件。  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230421194755261.png" alt="image-20230421194755261" style="zoom:40%;" />

<p>这里之所以有 8 个启动文件，是因为对于不同容量的芯片启动文件不一样。对于 103 系列，主要是用其中 3 个启动文件：  </p>
<figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">startup_stm32f10x_ld.s ： 适用于小容量 产品</span><br><span class="line">startup_stm32f10x_md.s ： 适用于中等容量产品</span><br><span class="line">startup_stm32f10x_hd.s ： 适用于大容量产品</span><br></pre></td></tr></table></figure>

<blockquote>
<p>这里的容量是指 FLASH 的大小.判断方法如下：</p>
<p>小容量： FLASH ≤ 32K<br>中容量： 64K≤FLASH ≤ 128K<br>大容量： 256K ≤ FLASH</p>
</blockquote>
<p>STM32F103ZET6和stm32F103RCT6芯片都属于大容量产品，所以我们的启动文件选择 startup_stm32f10x_hd.s，对于中等容量芯片请要选择 startup_stm32f10x_md.s 启动文件，小容量芯片选择 startup_stm32f10x_ld.s。启动文件到底什么作用，其实我们可以打开启动文件进去看看。启动文件主要是进行堆栈之类的初始化， 中断向量表以及中断函数定义。启动文件要引导进入 main 函数。 Reset_Handler中断函数是唯一实现了的中断处理函数，其他的中断函数基本都是死循环，启动文件我们后边会详细的去分析。   </p>
<ul>
<li>其他几个文件</li>
</ul>
<p>还有其他几个文件 stm32f10x_it.c,stm32f10x_it.h 以及 stm32f10x_conf.h 等文件。 stm32f10x_it.c 里面是用来编写中断服务函数，中断服务函数也可以随意编写在工程里面的任意一个文件里面。stm32f10x_conf.h 文件打开可以看到一堆的#include，这里建立工程的时候，可以注释掉一些不用的外设头文件。</p>
<h3 id="4-2-HAL库"><a href="#4-2-HAL库" class="headerlink" title="4.2 HAL库  "></a><font size=3>4.2 HAL库  </font></h3><p>HAL 是 Hardware Abstraction Layer 的缩写，即硬件抽象层。是 ST 为可以更好的确保跨STM32 产品的最大可移植性而推出的 MCU 操作库。这种程序设计由于抽离应用程序和硬件底层的操作， 更加符合跨平台和多人协作开发的需要。</p>
<p>HAL 库是基于一个非限制性的 BSD 许可协（Berkeley Software Distribution）而发布的开源代码。 ST 制作的中间件堆栈（USB 主机和设备库， STemWin）带有允许轻松重用的许可模式，只要是在 ST 公司的 MCU 芯片上使用，库中的中间件(USB 主机&#x2F;设备库,STemWin)协议栈即被允许修改，并可以反复使用。至于基于其它著名的开源解决方案商的中间件（ FreeRTOS，FatFs， LwIP 和 PolarSSL）也都具有友好的用户许可条款。</p>
<p>HAL 库是从 ST 公司从自身芯片的整个生产生态出发，为了方便维护而作的一次整合， 以改变标准外设库带来各系列芯片操作函数结构差异大、分化大、不利于跨系列移植的情况。相比标准外设库， STM32Cube HAL 库表现出更高的抽象整合水平， HAL 库的 API 集中关注各外设的公共函数功能，这样便于定义一套通用的用户友好的 API 函数接口，从而可以轻松实现从一个 STM32 产品移植到另一个不同的 STM32 系列产品。但由于封闭函数为了适应最大的兼容性， HAL 库的一些代码实际上的执行效率要远低于寄存器操作。但即便如此， HAL 库仍是 ST未来主推的库。  </p>
<p>STM32Cube 目前几乎支持 STM32 全系列，我主要是使用的STM32F1系列，所以这里主要写STM32CubeF1 相关知识。如果使用的是其他系列的 STM32 芯片，请到ST 官网下载对应的 STM32Cube 包即可。  </p>
<h4 id="4-2-1-HAL库能做什么"><a href="#4-2-1-HAL库能做什么" class="headerlink" title="4.2.1 HAL库能做什么"></a><font size=3>4.2.1 HAL库能做什么</font></h4><p>使用标准库可以忽略很多芯片寄存器的细节，根据提供的接口函数快速配置和使用一个 STM32 芯片， 使用 HAL 库也是如此。 不论何种库， 本质都是配置指定寄存器使芯片工作在我们需要的工作模式下。 HAL 库在设计的时候会更注重软硬件分离。HAL 库的 API 集中关注各个外设的公共函数功能，便于定义通用性更好、更友好的 API 函数接口，从而具有更好的可移植性。 HAL 库写的代码在不同的 STM32 产品上移植，非常方便。</p>
<p>我们需要学会调用 HAL 库的 API 函数，配置对应外设按照我们的要求工作，这就是 HAL库能做的事。但是无论库封装得多高级，最终还是要通过配置寄存器来实现。所以我们学习 HAL库的同时，也建议同时学习外设的工作原理和寄存器的配置。</p>
<p>HAL 库还可以和 STM32CubeMX（图形化软件配置工具）配套一起使用，开发者可以使用该工具进行可视化配置，并且自动生成配置好的初始化代码，大大的节省开发时间。  </p>
<h4 id="4-2-2-文件下载"><a href="#4-2-2-文件下载" class="headerlink" title="4.2.2 文件下载"></a><font size=3>4.2.2 文件下载</font></h4><p>在哪下载？还是在官网：<a target="_blank" rel="noopener" href="https://www.st.com/zh/embedded-software/stm32cubef1.html#get-software">STM32CubeF1 - STM32Cube MCU包，用于STM32F1系列（HAL、底层API和CMSIS（CORE、DSP和RTOS）、USB、TCP&#x2F;IP、File system、RTOS和Graphic - 附带在以下ST板上运行的示例：STM32 Nucleo、探索套件和评估板） - 意法半导体STMicroelectronics</a></p>
<p>网页登陆：<a target="_blank" rel="noopener" href="https://www.st.com/content/st_com/en.html">st.com&#x2F;content&#x2F;st_com&#x2F;en.html</a>，在打开的页面中依次选择：“【Tools &amp; Software】&rarr;【Ecosystem】&rarr;【STM32Cube】 &rarr;【新页面】&rarr;【Prodcut selector】， 如图  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113114453925.png" alt="image-20240113114453925" />

<p>在展开的页面中选择我们需要和固件，这展开“STM32CubeF1”即可看到我们需要的 F1 的安装包， 按下图操作， 在新的窗口中拉到底部，选择适合自己的下载方式， 注册帐号即可获取相应的驱动包。  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113114632225.png" alt="image-20240113114632225" />

<p>官网同时还未我们提供了一个git仓库：<a target="_blank" rel="noopener" href="https://github.com/STMicroelectronics/STM32CubeF1">GitHub - STMicroelectronics&#x2F;STM32CubeF1: STM32Cube MCU Full Package for the STM32F1 series - (HAL + LL Drivers, CMSIS Core, CMSIS Device, MW libraries plus a set of Projects running on all boards provided by ST (Nucleo, Evaluation and Discovery Kits))</a></p>
<p>通过这两种途径，我们都可以下载。</p>
<h4 id="4-2-3-HAL库介绍"><a href="#4-2-3-HAL库介绍" class="headerlink" title="4.2.3 HAL库介绍"></a><font size=3>4.2.3 HAL库介绍</font></h4><p>我们通过这种途径下载的固件包其实是HAL库，后边再介绍这个库与标准库的关系，现在我们看一下这个固件包的目录结构：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230421200129597.png" alt="image-20230421200129597" style="zoom:50%;" />



<ul>
<li><p>“ Documentation”： 里面是固件包的详细说明文档；</p>
</li>
<li><p>“ Drivers”：Drivers 文件夹包含 BSP， CMSIS 和 STM32F1xx_HAL_Driver 三个子文件夹。</p>
</li>
</ul>
<p>（1）BSP 文件夹 ：也叫板级支持包，此支持包提供的是直接与硬件打 交道的 API，例如触摸屏， LCD， SRAM 以及 EEPROM 等板载硬件资源等驱动。 BSP 文件夹下面有多种 ST 官方 Discovery开发板, Nucleo开发板以及 EVAL 板的 硬件驱动 API 文件，每一种开发板对应一个文件夹。</p>
<p>（2）CMSIS 文件夹：Cortex微控制器软件接口标准（ Cortex Microcontroller Software Interface Standard） ，包含STM32F1符合CMSIS标准的软件抽象层相关文件。文件夹内部文件比较多。主要包括 DSP 库(DSP_LIB 文件夹)， Cortex-M 内核及其设备文件 （Include 文件夹）， 微控制器专用头文件&#x2F;启动代码&#x2F; 专用系统文件等(Device 文件夹)。</p>
<p>（3）STM32F1xx_HAL_Driver 文件夹：这个文件夹非常重要，它包含了所有的 STM32F1xx 系列 HAL 库头文件和源文件，也就是所有底层硬件 抽象层 API 声明和定义。它的作用是屏蔽了复杂的硬件寄存器操作，统一了外设的接口函数。该文件夹包含 Src 和 Inc 两个子文件夹，其中 Src 子文件夹 存放的是.c 源文件， Inc 子文件夹存放的是与之对应 的.h 头文件。每个.c 源文件对应一个.h 头文件。比如gpio相关的 API 的声明和定义在文 件 stm32f1xx_hal_gpio.h 和 stm32f1xx_hal_gpio.c 中。 </p>
<ul>
<li>“ Middlewares”：该文件夹下面有 ST 和 Third_Party 两个子文件夹。  ST 文件夹下面存放的是 STM32 相关的一些文件，包括 STemWin 和 USB 库等。Third_Party 文件夹是第三方中间件，这些中间价都是非常成熟的开源解决方案。</li>
</ul>
<p>（1）ST 子文 件夹</p>
<table>
<thead>
<tr>
<th>文件夹</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>STemWin 文件夹</td>
<td>ST提供的图形GUI库“ STemWin” 。</td>
</tr>
<tr>
<td>STM32_USB_Device_Library 文件夹</td>
<td>USB 从机设备支持包。</td>
</tr>
<tr>
<td>STM32_USB_Host_Library 文件夹</td>
<td>USB 主机设备支持包。</td>
</tr>
</tbody></table>
<p>（2）Third_Party 子文件夹</p>
<table>
<thead>
<tr>
<th>文件夹</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>FatFs 文件夹</td>
<td>FAT 文件系统支持包。采用的 FATFS 文件系统。</td>
</tr>
<tr>
<td>FreeRTOS 文件夹</td>
<td>FreeRTOS 实时系统支持包。</td>
</tr>
<tr>
<td>LwIP 文件夹</td>
<td>LwIP 网络通信协议支持包。</td>
</tr>
</tbody></table>
<ul>
<li>“ Projects”： 以ST官方公板为载体，提供的外设应用示例，比如GPIO、 UART、 ADC、 RTC等。这些实例工程是可以直接编译的，每个文件夹对应一个 ST 官方的 Demo板。每个工程下面都有一个 MDK-ARM子文件夹，该子文件夹内部会有名称为 Project.uvprojx 的工程文件，我们只需要点击它就可以<br>在 MDK 中打开工程。  例如，下图就是Project目录下的一个UART的串口例程，我们双击下边的Project.uvprojx文件就可以打开这个工程。</li>
</ul>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230421215634134.png" alt="image-20230421215634134" style="zoom:33%;" />

<ul>
<li>“ Utilities”：一些字体、日志、多媒体等杂项示例，日常使用的并不多。</li>
<li>其它几个文件</li>
</ul>
<p>文件夹中还有几个单独的文件， 用于声明软件版本或者版权信息， 我们使用 ST 的芯片已经默认得到这个软件的版权使用授权，可以简单了解一下各文件的内容，实际项目中我们一般不添加。</p>
<p>License.md：用于声明软件版权信息的文件。</p>
<p>package.xml： 描述固件包版本信息的文件。</p>
<p>Release_Notes.html：超文本文件，用浏览器打开可知它是对固件包的补充描述和固件版本更新的记录说明。  </p>
<h4 id="4-2-4-CMSIS-文件夹关键文件"><a href="#4-2-4-CMSIS-文件夹关键文件" class="headerlink" title="4.2.4 CMSIS 文件夹关键文件  "></a><font size=3>4.2.4 CMSIS 文件夹关键文件  </font></h4><p>我们来分析一下 CMSIS 文件夹：由命名可知， 该文件夹和前面提到的 CMSIS 标准是一致的， CMSIS 为软件包的内容制定了标准， 包括文件目录的命名和内容构成， 5.7.0 版本CMSIS 规定软件包目录如表：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113115532703.png" alt="image-20240113115532703" />

<p>知道了 CMSIS 规定的组件及其文件目录的大概内容后，我们再来看看 ST 提供的 CMSIS文件夹，如上节提到的， 它的位置是“ STM32Cube_FW_F1_V1.8.0&#x2F;Drivers&#x2F;CMSIS”。打开文件夹内容如下图所示， 可以发现它的目录结构完全按照 CMSIS 标准执行， 仅仅是作了部分删减。  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113115609165.png" alt="image-20240113115609165" style="zoom: 80%;" />

<p>CMSIS 文件夹中的 Device 和 Include 这两个文件夹中的文件是我们工程中最常用到的。下面对这两个文件夹作简单的介绍：  </p>
<ul>
<li>（1）Device 文件夹</li>
</ul>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113120512319.png" alt="image-20240113120512319" style="zoom:50%;" />

<ul>
<li>（2）Include 文件夹</li>
</ul>
<p>Include 文件夹存放了符合 CMSIS 标准的 Cortex-M 内核头文件。 对于 STM32F1 的工程，我们只要把我们需要的添加到工程即可，需要的头文件有： cmsis_armcc.h、 cmsis_armclang.h、 cmsis_compiler.h、 cmsis_version.h、core_cm3.h 和 mpu_armv7.h。这几个头文件，对比起来，我们会比较多接触的是 core_cm3.h。core_cm3.h 是内核底层的文件，由 ARM 公司提供，包含一些 AMR 内核指令， 如软件复位， 开关中断等功能。今后在需要的例程再去讲解其程序，现在要提到的是它包含了一个重要的头文件 stdint.h。  </p>
<p>stdint.h 是从 c99 中引进的一个标准 C 库的文件。在 2000 年 3 月， ANSI 采纳了 C99 标准。 ANSI C 被几乎所有广泛使用的编译器（如： MDK、 IAR） 支持。多数 C 代码是在 ANSI C基础上写的。任何仅使用标准 C 并且不和硬件相关的代码， 在任意平台上用遵循 ANSI C 标准的编译器下能编译成功。 就是说这套标准不依赖硬件，独立于任何硬件，可以跨平台。stdint.h 可以在 MDK 安装目录下找到，如 MDK5 安装在 C 盘时，可以在路径：C:\Keil_v5\ARM\ARMCC\include 找到。 stdint.h 的作用就是提供了类型定义，其部分类型定义代码如下：    </p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* exact-width signed integer types */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">signed</span> <span class="type">char</span> <span class="type">int8_t</span>;</span><br><span class="line"><span class="keyword">typedef</span> <span class="type">signed</span> <span class="type">short</span> <span class="type">int</span> <span class="type">int16_t</span>;</span><br><span class="line"><span class="keyword">typedef</span> <span class="type">signed</span> <span class="type">int</span> <span class="type">int32_t</span>;</span><br><span class="line"><span class="keyword">typedef</span> <span class="type">signed</span> __INT64 <span class="type">int64_t</span>;</span><br><span class="line"><span class="comment">/* exact-width unsigned integer types */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">unsigned</span> <span class="type">char</span> <span class="type">uint8_t</span>;</span><br><span class="line"><span class="keyword">typedef</span> <span class="type">unsigned</span> <span class="type">short</span> <span class="type">int</span> <span class="type">uint16_t</span>;</span><br><span class="line"><span class="keyword">typedef</span> <span class="type">unsigned</span> <span class="type">int</span> <span class="type">uint32_t</span>;</span><br><span class="line"><span class="keyword">typedef</span> <span class="type">unsigned</span> __INT64 <span class="type">uint64_t</span>;</span><br></pre></td></tr></table></figure>

<h4 id="4-2-5-关键文件介绍补充笔记"><a href="#4-2-5-关键文件介绍补充笔记" class="headerlink" title="4.2.5 关键文件介绍补充笔记"></a><font size=3>4.2.5 关键文件介绍补充笔记</font></h4><ul>
<li>（1）HAL 库关键文件介绍如下表 ：</li>
</ul>
<table>
<thead>
<tr>
<th>文件</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td>sm32f1xx_hal.c</td>
<td>包含 HAL 通用 API（比如 HAL_Init,HAL_DeInit,HAL_Delay 等）。</td>
</tr>
<tr>
<td>stm32f1xx_hal.h</td>
<td>HAL 的头文件，它应被客户代码所包含。</td>
</tr>
<tr>
<td>stm32f1xx_hal_conf.h</td>
<td>HAL 的配置文件，主要用来选择使能何种外 设以及一些时钟相关参数设置。其本身应该 被客户代码所包含。</td>
</tr>
<tr>
<td>stm32f1xx_hal_def.h</td>
<td>包含 HAL 的通用数据类型定义和宏定义</td>
</tr>
</tbody></table>
<ul>
<li>（2）stm32f1xx_it.c&#x2F;stm32f1xx_it.h 文件</li>
</ul>
<p>stm32f1xx_it.h 中主要是一些中断服务函数的申明。stm32f1xx_it.h 中是这些中断服务函数定义，而这些函数定义除了 Systick 中断服务函数SysTick_Handler 外基本都是空函数，没有任何控制逻辑。一般情况下，我们可以去掉这两个文件，然后把中断服务函数写在工程中的任何一个可见文件中。  </p>
<ul>
<li>（3）stm32f1xx.h 头文件</li>
</ul>
<p>头文件 stm32f1xx.h 是所有 stm32f1 系列的顶层头文件。使用 STM32F1 任何型号的芯片，都需要包含这个头文件。同时，因为 stm32f1 系列芯片型号非常多， ST 为每种芯片型号定义了一个特有的片上外设访问层头文件，比如 STM32F103系列， ST 定义了一个头文件 stm32f103xx.h，然后 stm32f1xx.h 顶层头文件会根据工程芯片型号，来选择包含对应芯片的片上外设访问层头文件。我们可以打开 stm32f1xx.h 头文件可以看到，里面有如下几行代码：  </p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">if</span> defined(STM32F100xB)</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;stm32f100xb.h&quot;</span></span></span><br><span class="line"><span class="comment">// ... ...</span></span><br><span class="line"><span class="meta">#<span class="keyword">elif</span> defined(STM32F101xE)</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;stm32f101xe.h&quot;</span></span></span><br><span class="line"><span class="comment">// ... ...</span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">error</span> <span class="string">&quot;Please select first the target STM32F1xx device used in your application(in stm32f1xx.h file)&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure>

<p>我们以 stm3f103 为例，如果定义了宏定义标识符 STM32F103xx，那么头文件 stm32f1xx.h 将会包含头文件 stm32f103xx.h。所以头文件 stm32f103xx.h 一定会被整个工程所引用。  </p>
<ul>
<li>（4）stm32f103xx.h 头文件</li>
</ul>
<p>stm32f103xx.h 是 stm32f103 系列芯片通用的片上外设访问层头文件，只要我们进行 stm32f103 开发，就必然要使用到该文件。打开该文件我们可以看到里面主要是一些结构体和宏定义标识符。这个文件的主要作用是寄存器定义声明以及封装内存操作。</p>
<ul>
<li>（5）system_stm32f1xx.c&#x2F;system_stm32f1xx.h 文件</li>
</ul>
<p>头文件system_stm32f1xx.h和源文件system_stm32f1xx.c主要是声明和定义了系统初始化函数 SystemInit 以及系统时钟更新函数SystemCoreClockUpdate。 SystemInit 函数的作用是进行时钟系统的一些初始化操作以及中断向量表偏移地址设置，但它并没有设置具体的时钟值，<strong>这是与标准库的最大区别</strong>，在使用标准库的时候， SystemInit 函数会帮我们配置好系统时钟配置相关的各个寄存器。在启动文件 startup_stm32f103xx.s 中会设置系统复位后，直接调用 SystemInit 函数进行系统初始化。 SystemCoreClockUpdate 函数是在系统时钟配置进行修改后，调用这个函数来更新全局变量 SystemCoreClock 的值，变量 SystemCoreClock 是一个全局变量，开放这个变量可以方便我们在用户代码中直接使用这个变量来进行一些时钟运算。  </p>
<ul>
<li>（6）stm32f1xx_hal_msp.c 文件</li>
</ul>
<p>MSP，全称为 MCU support package，这里大家只需要知道，函数名字中带有 MspInit 的函数，它们的作用是进行 MCU 级别硬件初始化设置，并且它们通常会被上一层的初始化函数所调用，这样做的目的是为了把MCU相关的硬件初始化剥夺出来，方便用户代码在不同型号的MCU上移植。 </p>
<p>stm32f1xx_hal_msp.c 文件定义了两个函数 HAL_MspInit 和 HAL_MspDeInit。这两个函数分别被文件 stm32f1xx_hal.c 中的 HAL_Init 和 HAL_DeInit 所调用。 HAL_MspInit 函数的主要作用是进行 MCU 相关的硬件初始化操作。例如我们要初始化某些硬件，我们可以硬件相关的初始化配置写在 HAL_MspDeinit 函数中。这样的话，在系统启动后调用了 HAL_Init之 后 ， 会自动调用硬件初始化函数 。实际上，我们在工程模板中直接删掉stm32f1xx_hal_msp.c 文件也不会对程序运行产生任何影响。</p>
<ul>
<li>（7）startup_stm32f103xe.s 启动文件</li>
</ul>
<p>STM32 系列所有芯片工程都会有一个.s 启动文件。对于不同型号的 stm32 芯片启动文件也是不一样的。我们的开发板是 STM32F103 系列，所以我们需要使用与之对应的启动文件startup_stm32f103xe.s。启动文件的作用主要是进行堆栈的初始化，中断向量表以及中断函数定义等。启动文件有一个很重要的作用就是系统复位后引导进入 main 函数。打开启动文件 startup_stm32f103xe.s，可以看到下面几行代码：  </p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">; Reset handler</span><br><span class="line">Reset_Handler PROC</span><br><span class="line">    EXPORT Reset_Handler [WEAK]</span><br><span class="line">    IMPORT __main</span><br><span class="line">    IMPORT SystemInit</span><br><span class="line">    LDR R0, =SystemInit</span><br><span class="line">    BLX R0</span><br><span class="line">    LDR R0, =__main</span><br><span class="line">    BX R0</span><br><span class="line">    ENDP</span><br></pre></td></tr></table></figure>

<p>Reset_Handler 在我们系统启动的时候会执行，这几行代码的作用是在系统启动之后，首先调用 SystemInit 函数进行系统初始化，然后引导进入 main 函数执行用户代码。  </p>
<h4 id="4-2-6-weak-修饰符"><a href="#4-2-6-weak-修饰符" class="headerlink" title="4.2.6 __weak 修饰符  "></a><font size=3>4.2.6 __weak 修饰符  </font></h4><p>在 HAL 库中，很多回调函数前面使用__weak 修饰符，weak 顾名思义是“弱”的意思，所以如果函数名称前面加上__weak 修饰符，我们一般称这个函数为“弱函数”。加上了__\weak 修饰符的函数，用户可以在用户文件中重新定义一个同名函数，最终编译器编译的时候，会选择用户定义的函数，如果用户没有重新定义这个函数，那么编译器就会执行__weak 声明的函数，并且编译器不会报错。</p>
<p>比如我们打开工程模板（后边再建），找到并打开文件stm32f1xx_hal.c 文件，里面定义了一个函数 HAL_MspInit，定义如下：  </p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">__weak <span class="type">void</span> <span class="title function_">HAL_MspInit</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>可以看出， HAL_MspInit 函数前面有加修饰符__weak。同时，在该文件的前面有定义函数HAL_Init，并且 HAL_Init 函数中调用了函数 HAL_MspInit。  </p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">HAL_StatusTypeDef <span class="title function_">HAL_Init</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">//此处省略部分代码</span></span><br><span class="line">    HAL_MspInit();</span><br><span class="line">    <span class="keyword">return</span> HAL_OK;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>如果我们没有在工程中其他地方重新定义 HAL_MspInit()函数，那么 HAL_Init 初始化函数执行的时候，会默认执行 stm32f1xx_hal.c 文件中定义的 HAL_MspInit 函数，而这个函数没有任何控制逻辑。如果用户在工程中重新定义函数 HAL_MspInit，那么调用 HAL_Init 之后，会执行用户自己定义的 HAL_MspInit 函数而不会执行 stm32f1xx_hal.c 默认定义的函数。也就是说，表面上我们看到函数 HAL_MspInit 被定义了两次，但是因为有一次定义是弱函数，使用了__weak修饰符，所以编译器不会报错。  </p>
<p>__weak 在回调函数的时候经常用到。这样的好处是，系统默认定义了一个空的回调函数，保证编译器不会报错。同时，如果用户自己要定义用户回调函数，那么只需要重新定义即可，不需要考虑函数重复定义的问题，使用非常方便，在 HAL 库中__weak 关键字被广泛使用。  </p>
<h4 id="4-2-7-Msp-回调函数执行过程"><a href="#4-2-7-Msp-回调函数执行过程" class="headerlink" title="4.2.7 Msp 回调函数执行过程  "></a><font size=3>4.2.7 Msp 回调函数执行过程  </font></h4><p>我们打开一个下载的固件库包中的工程，看一下工程长啥样，我们选择下边路径中的这个UART串口工程实例：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">STM32Cube_FW_F1_V1<span class="number">.8</span><span class="number">.0</span>\Projects\STM3210E_EVAL\Examples\UART\UART_Printf\MDK-ARM</span><br></pre></td></tr></table></figure>

<p>我们来看一下串口的初始化：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20230421222938085.png" alt="image-20230421222938085" style="zoom:50%;" />

<p>用户在main函数中直接初始化串口，设置串口 相关参数，包括波特率，停止位，奇偶校验位等，并且最终是通过调用 HAL_UART_Init 函数进行参数设置。在函数 HAL_UART_Init 内部，通过判断逻辑判断如果串口还没有进行初始话，那么会调用函数HAL_UART_MspInit 进行相关初始化设置 。同时，我们可以看到，在文件 stm32f1xx_hal_uart.c 内部，有定义一个弱函数 HAL_UART_MspInit：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// stm32f1xx_hal_uart.c</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">  * @brief  UART MSP Init.</span></span><br><span class="line"><span class="comment">  * @param  huart  Pointer to a UART_HandleTypeDef structure that contains</span></span><br><span class="line"><span class="comment">  *                the configuration information for the specified UART module.</span></span><br><span class="line"><span class="comment">  * @retval None</span></span><br><span class="line"><span class="comment">  */</span></span><br><span class="line">__weak <span class="type">void</span> <span class="title function_">HAL_UART_MspInit</span><span class="params">(UART_HandleTypeDef *huart)</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="comment">/* Prevent unused argument(s) compilation warning */</span></span><br><span class="line">  UNUSED(huart);</span><br><span class="line">  <span class="comment">/* <span class="doctag">NOTE:</span> This function should not be modified, when the callback is needed,</span></span><br><span class="line"><span class="comment">           the HAL_UART_MspInit could be implemented in the user file</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p> 而在 stm32f1xx_hal_msp.c 文件中对此函数进行了重写，重写后的函数 HAL_UART_MspInit 则主要进行串口 GPIO 引脚初始化设置。</p>
<p>这里定义的弱函数 HAL_UART_MspInit 是一个空函数，没有任何实际的控制逻辑。__weak 修饰符定义的弱函数如果用户自己重新定义了这个函数，那么会优先执行用户定义函数。所以，实际上在函数 HAL_UART_Init 内部调用的 HAL_UART_MspInit()函数，最终执行的是用户在 stm32f1xx_hal_msp.c  中自定义的HAL_UART_MspInit()函数。  </p>
<p>那么整个串口初始化的过程为： 【main.c】 &rarr; 【HAL_UART_Init()】&rarr; 【HAL_UART_MspInit()】。</p>
<blockquote>
<p>为什么串口相关初始化不在 HAL_UART_Init 函数内部一次初始化而还要调用函数 HAL_UART_MspInit()呢？</p>
<p>这实际就是 HAL 库的一个优点，它通过开放一个回调函数 HAL_UART_MspInit()，让用户自己去编写与串口相关的 MCU 级别的硬件初始化，而与 MCU 无关的串口参数相关的通用配置则放在 HAL_UART_Init。</p>
<p>我们要初始化一个串口，首先要设置和 MCU 无关的东西，例如波特率，奇偶校验，停止位等，这些参数设置和 MCU 没有任何关系，可以用STM32F1，也可以是 STM32F2&#x2F;F3&#x2F;F4&#x2F;F7上的串口。而一个串口设备它需要一个 MCU 来承载，例如用 STM32F1 来做承载， PA9 做为发送， PA10 做为接收， MSP 就是要初始化 STM32F1 的 PA9，PA10，配置这两个引脚。 所以 HAL驱动方式的初始化流程就是： HAL_USART_Init()&rarr;HAL_USART_MspInit() ， 先初始化与 MCU无关的串口协议 ，再初始化 与 MCU 相关的串口引脚 。在 STM32 的 HAL 驱动中HAL_PPP_MspInit()作为回调， 被 HAL_PPP_Init()函数所调用。 当我们需要移植程序到 STM32F1平台的时候，我们只需要修改 HAL_XXX_MspInit 函数内容而不需要修改 HAL_XXX_Init 入口参<br>数内容。</p>
<p>所以在 STM32 的 HAL 库中，大部分外设都有回调函数 HAL_MspInit()。  </p>
</blockquote>
<h4 id="4-2-8-HAL库中断处理"><a href="#4-2-8-HAL库中断处理" class="headerlink" title="4.2.8 HAL库中断处理"></a><font size=3>4.2.8 HAL库中断处理</font></h4><p>中断是 STM32 开发的一个很重要的概念，这里我们可以简单地理解为： STM32 暂停了当前手中的事并优先去处理更重要的事务。而这些“更重要的事务”是由软件开发人员在软件中定义的。关于 STM32 中断的概念。由于 HAL 库中断处理的逻辑比较统一，我们将这个处理过程抽象为下图所表示的业务逻辑：  </p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113121103358.png" alt="image-20240113121103358" style="zoom:50%;" />

<p>以上的流程大概就是： 设置外设的控制句柄结构体PPP_HandleType 和初始化 PPP_InitType 结构体的参数， 然后调用 HAL 库对应这个驱动的初始化 HAL_PPP_Init()，由于这个 API 中有针对外设初始化细节的接口 Hal_PPP_Mspinit()， 我们需要重新实现这个函数并完成外设时钟、 IO 等细节差异的设置，完成各细节处理后，使用HAL_NVIC_SetPriority()、 HAL_NVIC_EnableIRQ()来使能我们的外设中断；定义中断处理函数 PPP_IRQHandler ，并在中断函数中调用 HAL_ppp_function_IRQHandler()来判断和处理中断标记； HAL 库中断处理完成后，根据对应中的调用我们需要自定义的中断回调接口 HAL_PPP_ProcessCpltCallback();如串口接收函数 HAL_UART_RxCpltCallback()， 我们在这个函数中实现我们对串口接收数据想做的处理;中断响应处理完成后， stm32 芯片继续顺序执行我们定义的主程序功能，按照以上处理的标准流程完成了一次中断响应。  </p>
<h3 id="4-3-LL库"><a href="#4-3-LL库" class="headerlink" title="4.3 LL库"></a><font size=3>4.3 LL库</font></h3><p>LL 库（Low Layer）目前与 HAL 库捆绑发布，它设计为比 HAL 库更接近于硬件底层的操作，代码更轻量级， 代码执行效率更高的库函数组件， 可以完全独立于 HAL 库来使用，但 LL库不匹配复杂的外设，如 USB 等。所以 LL 库并不是每个外设都有对应的完整驱动配置程序。使用 LL 库需要对芯片的功能有一定的认知和了解,它可以：    </p>
<ul>
<li>独立使用，该库完全独立实现，可以完全抛开 HAL 库，只用 LL 库编程完成。</li>
<li>混合使用，和 HAL 库结合使用。</li>
</ul>
<p>对于 HAL 库和 LL 库的关系， 如下图的软件框架所示， 可以看出它们设计为彼此独立的分支， 但又同属于 HAL 库体系。</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV16-STM32%E5%BC%80%E5%8F%91/LV16-03-STM32%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/img/image-20240113114126151.png" alt="image-20240113114126151" style="zoom:50%;" />


    </div>

    
    
    

    <footer class="post-footer">




    <div>
        
            <div style="text-align:center;color: #ccc;font-size:14px;">
            ----------本文结束
            <i class="fas fa-fan fa-spin" style="color: #FF1493; font-size: 1rem"></i>
            感谢您的阅读----------
            </div>
        
    </div>





  
  <div class="my_post_copyright"> 
    <p><span>文章标题:</span><a href="/post/c2c37802.html">LV16-03-STM32基础知识</a></p>
    <p><span>文章作者:</span><a href="/" title="欢迎访问 《苏木》 的学习笔记">苏木</a></p>
    <p><span>发布时间:</span>2023年06月04日 - 22:06</p>
    <p><span>最后更新:</span>2025年06月14日 - 00:25</p>
    <p><span>原始链接:</span><a href="/post/c2c37802.html" title="LV16-03-STM32基础知识">https://sumumm.github.io/post/c2c37802.html</a></p>
    <p><span>许可协议:</span><i class="fab fa-creative-commons"></i> <a rel="license" href= "https://creativecommons.org/licenses/by-nc-nd/4.0/" target="_blank" title="Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)">署名-非商业性使用-禁止演绎 4.0 国际</a> 转载请保留原文链接及作者。</p>  
  </div>
  


          <div class="post-tags">
              <a href="/tags/LV16-STM32%E5%BC%80%E5%8F%91/" rel="tag"><i class="fa fa-tag"></i> LV16-STM32开发</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/post/f9aa55e5.html" rel="prev" title="LV16-04-STM32工程创建">
                  <i class="fa fa-angle-left"></i> LV16-04-STM32工程创建
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/post/c30a7dbc.html" rel="next" title="LV16-02-常见存储器">
                  LV16-02-常见存储器 <i class="fa fa-angle-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">

  <div class="copyright">
    &copy; 2017 – 
    <span itemprop="copyrightYear">2025</span>
    <span class="with-love">
      <i class="fa fa-heart"></i>
    </span>
    <span class="author" itemprop="copyrightHolder">苏木</span>
  </div>
<div class="wordcount">
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-line"></i>
    </span>
      <span>站点总字数：</span>
    <span title="站点总字数">3.7m</span>
  </span>
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span>站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">225:26</span>
  </span>
</div>




    <span id="sitetime"></span>
    <script defer language=javascript>
        function siteTime()
        {
            window.setTimeout("siteTime()", 1000);
            var seconds = 1000;
            var minutes = seconds * 60;
            var hours = minutes * 60;
            var days = hours * 24;
            var years = days * 365;
            var today = new Date();
            var todayYear = today.getFullYear();
            var todayMonth = today.getMonth()+1;
            var todayDate = today.getDate();
            var todayHour = today.getHours();
            var todayMinute = today.getMinutes();
            var todaySecond = today.getSeconds();
            /*==================================================
            Date.UTC() -- 返回date对象距世界标准时间(UTC)1970年1月1日午夜之间的毫秒数(时间戳)
            year        - 作为date对象的年份，为4位年份值
            month       - 0-11之间的整数，做为date对象的月份
            day         - 1-31之间的整数，做为date对象的天数
            hours       - 0(午夜24点)-23之间的整数，做为date对象的小时数
            minutes     - 0-59之间的整数，做为date对象的分钟数
            seconds     - 0-59之间的整数，做为date对象的秒数
            microseconds - 0-999之间的整数，做为date对象的毫秒数
            ==================================================*/
            var t1 = Date.UTC(2017, 
                              5, 
                              19, 
                              0, 
                              0, 
                              0); //北京时间
            var t2 = Date.UTC(todayYear,todayMonth,todayDate,todayHour,todayMinute,todaySecond);
            var diff = t2-t1;
            var diffYears = Math.floor(diff/years);
            var diffDays = Math.floor((diff/days)-diffYears*365);
            var diffHours = Math.floor((diff-(diffYears*365+diffDays)*days)/hours);
            var diffMinutes = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours)/minutes);
            var diffSeconds = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours-diffMinutes*minutes)/seconds);
            document.getElementById("sitetime").innerHTML="已在这里 "+diffYears+" 年 "+diffDays+" 天 "+diffHours+" 小时 "+diffMinutes+" 分钟 "+diffSeconds+" 秒";
        }
        siteTime();
    </script>



    </div>
  </footer>

  
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/next-theme-pjax/0.6.0/pjax.min.js" integrity="sha256-vxLn1tSKWD4dqbMRyv940UYw4sXgMtYcK6reefzZrao=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.umd.js" integrity="sha256-ytMJGN3toR+a84u7g7NuHm91VIR06Q41kMWDr2pq7Zo=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lozad.js/1.16.0/lozad.min.js" integrity="sha256-mOFREFhqmHeQbXpK2lp4nA3qooVgACfh88fpJftLBbc=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script><script src="/js/pjax.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>




  <script src="/js/third-party/fancybox.js"></script>

  <script src="/js/third-party/pace.js"></script>


  




  

  <script class="next-config" data-name="enableMath" type="application/json">true</script><script class="next-config" data-name="mathjax" type="application/json">{"enable":true,"tags":"none","js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.js","integrity":"sha256-MASABpB4tYktI2Oitl4t+78w/lyA+D7b/s9GEP0JOGI="}}</script>
<script src="/js/third-party/math/mathjax.js"></script>


 
        <div id="click-show-text"
            data-mobile = false
            data-text = 富强,民主,文明,和谐,自由,平等,公正,法制,爱国,敬业,诚信,友善
            data-fontsize = 15px
            data-random= false>
        </div>
       

      
        <script async src=https://cdn.jsdelivr.net/npm/hexo-next-mouse-effect@latest/click/showText.js></script>
      

      
    




    <script async src="/js/fancybox_param.js"></script>





<!-- APlayer本体 -->



</body>
</html>
